Compare commits
91 Commits
49c75768ba
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 69d6bf86ab | |||
| 2ede8c85a7 | |||
| e7f0f0ee71 | |||
| 306c8df92c | |||
| 08d451fb3c | |||
| 3394ba9650 | |||
| cac8379aa7 | |||
| eb8c1f8609 | |||
| 5eb136b60a | |||
| e09a150cc7 | |||
| cc7825a959 | |||
| 6bb2a732ec | |||
| e6fc0aec2a | |||
| 3da6a5f3f8 | |||
| ffed3be614 | |||
| 8dda30a742 | |||
| 218930d454 | |||
| 8bd068c68e | |||
| 41c02bca59 | |||
| ba3a1426c2 | |||
| 116f1af7dd | |||
| f667c69674 | |||
| 6c4f1f339a | |||
| 4870b0c7d6 | |||
| f1654f2d43 | |||
| 2358b986a8 | |||
| 9f6b247a4a | |||
| fc94f7c534 | |||
| a43a5853e1 | |||
| b4e1ebbd70 | |||
| 158125c257 | |||
| 4c79936f7c | |||
| 2cbe05318d | |||
| c3de90989b | |||
| c505c0c6c7 | |||
| 3e635b285e | |||
| 00320f328c | |||
| 47e3bb630d | |||
| c0975bf238 | |||
| 0ecd665187 | |||
| 8084a603de | |||
| eac1cfe878 | |||
| ce05c6af9f | |||
| 4eb2545acd | |||
| 8151183f10 | |||
| 75c5abc040 | |||
| a3fcb3c78e | |||
| a9788fe669 | |||
| 9560c6b40f | |||
| 7d8c36a771 | |||
| f03ec900c6 | |||
| faeb18807e | |||
| cee5c3b7f9 | |||
| dfcce13d3e | |||
| fa71627030 | |||
| a5792218a5 | |||
| 07f251f119 | |||
| 24506cea6a | |||
| 186bca77b4 | |||
| 714f5d0bff | |||
| 0f4991e745 | |||
| b536b4c7ad | |||
| c34213c616 | |||
| e224f8f252 | |||
| 6ba6bcb6ee | |||
| 8d72ff526f | |||
| afe47ace08 | |||
| 38f9045ebd | |||
| 08cb585468 | |||
| 7bbc58d03f | |||
| c7d06858b6 | |||
| 57d0f57924 | |||
| bc079a7874 | |||
| ad0d3d7f99 | |||
| 01cdad00c2 | |||
| fc1f762312 | |||
| 698094466d | |||
| c04a49f684 | |||
| fa1331b3e8 | |||
| 923afe3b87 | |||
| d9181075a1 | |||
| 0bd2125f24 | |||
| 8f8ed0084e | |||
| 43b8cfb296 | |||
| bd4a756e53 | |||
| 9e951cb7d8 | |||
| 38e5d938fe | |||
| 5cc5a11371 | |||
| bdb9042b44 | |||
| e6a55c1e01 | |||
| c9e37abc63 |
207
README.md
Normal file
@@ -0,0 +1,207 @@
|
||||
# What is CloudDeploy?
|
||||
|
||||
CloudDeploy is a script that mostly automates setting up a full "home cloud" environment, it is designed to allow non-technical users to install their own cloud.
|
||||
|
||||
CloudDeploy is meant to be run on a fresh ubuntu install (though in theory any linux distro with access to apt and the ubuntu apt repo's will work).
|
||||
|
||||
CloudDeploy cannot do everything, so it will optionally prompt the user during configuration to perform specific simple tasks (like resetting an account, making an account, etc)
|
||||
|
||||
CloudDeploy will also dynamically generate a "post-install" file, which contains all the things the user will need to do once the script is finished based on the options they chose during configuration.
|
||||
|
||||
Unlike other AIO software, CloudDeploy is not a fully integrated product. CloudDeploy deploys and integrates the following popular opensource docker containers, allowing users to then make modifications themselves:
|
||||
- dockge
|
||||
- nginx proxy manager
|
||||
- bookstack
|
||||
- owncloud
|
||||
- filebrowser (for management)
|
||||
- convertX
|
||||
- Heimdall
|
||||
- trantienloi's youtube downloader
|
||||
- dozzle
|
||||
- it-tools
|
||||
- jellyfin
|
||||
- uptime kuma
|
||||
- onlyoffice documentserver
|
||||
- pihole
|
||||
- nginx web site
|
||||
- vaultwarden
|
||||
- wireguard-easy
|
||||
|
||||
this method allows CloudDeploy based deployments to be easily modified and experimented with.
|
||||
|
||||
## quick-deploy:
|
||||
|
||||
pre-requisites: pre-installed ubuntu server machine with at least 8GB RAM, 4 cores, enough storage for your liking, a static ip and port-forwarding 443, 80 and 51820 from your router to that ip. a purchased DNS domain with an A record pointing @ to your public ip and a CNAME record pointing \* to @
|
||||
|
||||
run the following command:
|
||||
|
||||
`sudo apt update && sudo apt upgrade -y && sudo apt install git curl && sudo git clone https://git.sdgcloud.nl/SDGDen/CloudDeploy.git && cd CloudDeploy && sudo chmod a+x ./deploy.sh && sudo ./deploy.sh`
|
||||
|
||||
this will update your system, install git and curl (needed for the script to run), clone the repo, make the script runable and runs it.
|
||||
|
||||
below is more detailed instructions and explanations.
|
||||
|
||||
# Different options
|
||||
|
||||
CloudDeploy has a couple of options for deploying, primarily this is relating to how domain names are handled.
|
||||
|
||||
Purchasing a domain name is the only returning cost of the cloud deployed using CloudDeploy, everything else is free.
|
||||
|
||||
So you'll be asked to pick between 3 options:
|
||||
- 1: purchase and use a public domain name
|
||||
you'll have to set up two records: an A record for @ pointing to your public ip (google "what is my ip" to get your public ip) and a CNAME record for * pointing to @
|
||||
- 2: use your own DNS and VPN for external connections
|
||||
this means you *have* to use your DNS server (pihole) in order to be able to resolve the websites, which can only be accessed on your network locally or via VPN.
|
||||
for this, you'll have to configure some things on your router and your devices.
|
||||
- 3: use your own DNS both internally and externally
|
||||
this is like option 2, but you expose your own DNS to the internet, allowing you and others to use it and thus resolve your websites.
|
||||
|
||||
in options #1 and #3, you'll have to port-forward ports 443 and 80 (web traffic) to the ip of your machine. we'll get back to this later.
|
||||
|
||||
for all options, you have to port-forward port 51820 (VPN)
|
||||
|
||||
and for option 3, you'll have to port-forward port 53 (DNS), you can also do this for option 1 if you want your friends to be able to use your pihole
|
||||
|
||||
|
||||
# Setting Up from Scratch
|
||||
|
||||
to set up from scratch, we must begin with the hardware.
|
||||
|
||||
## hardware
|
||||
to run this cloud, you need at least 4GB of RAM, though 8GB is the realistic minimum and 16GB is recommended for multiple users (more than 16GB is not needed), this *can* be older RAM (like DDR3)
|
||||
you will also need *any* 4 core, 8 thread CPU and the fastest networking your network supports (usually gigabit ethernet internally)
|
||||
you do not need a GPU unless you plan on adding more components yourself (for example an LLM) later.
|
||||
|
||||
the important thing is the storage, the more storage you put in, the more storage you'll have available to you for your media on jellyfin and your files on owncloud.
|
||||
|
||||
if you have a system with 16+ GB RAM, more than 4 cores with hyperthreading and multiple hard drives, it is highly recommended to install ProxMox VE to it, make a raid-z1 pool of the hard drives and create an ubuntu VM on that rather than installing ubuntu directly. This allows you to add additional VMs to the server later and allows you to remotely reboot, shutdown, start and manage the VM. It also allows you to leverage Proxmox Backup Server on a separate device for backups if you'd like, and with raid-z1 you are protected against drive failure.
|
||||
|
||||
this does require better hardware, so it's not required. if you have an old Dell with 8GB RAM, 4 cores on a 4th gen i5 and a single 4TB harddrive, that'll work just fine, giving you and your family ~3.8TB of cloud storage.
|
||||
|
||||
## installing ubuntu
|
||||
if you are installing ubuntu directly, download the ubuntu server LTS ISO file from the official website and use software like rufus or balena etcher to flash the ISO file to any 4GB+ USB stick.
|
||||
|
||||
insert the USB stick into the computer and boot from it. you may have to press a button on your keyboard to enter the boot menu and select the USB stick manually there. This button differs per vendor, so check the documentation for your computer's manufacturer or for your motherboard's manufacturer if it uses aftermarket parts.
|
||||
|
||||
once you're booted into ubuntu server install, go through the steps.
|
||||
|
||||
|
||||
## ubuntu network configuration
|
||||
ensure that for the network configuration, you configure a static ip address.
|
||||
|
||||
for this, you'll want to get the network configuration for one of your existing devices first. the easiest is on windows:
|
||||
open a command prompt by pressing windows+x, then A (this only works if your windows is set to english)
|
||||
type in "ipconfig"
|
||||
you'll see 5 lines of text, but only the last 3 are important:
|
||||
|
||||
ip:
|
||||
this shows that devices ip
|
||||
|
||||
subnet mask:
|
||||
generally 255.255.255.0, which is equal to a /24 subnet. to convert these: imaging the subnet mask as 4 bytes (one byte can store 0-255 as an integer), the subnet value is how many of the bits in that 4 byte string are 1. in this case, 24 out of 32 are 1, the last 8 are 0. this is almost always the case for home networks. you may also see 255.255.0.0 (/16), 255.0.0.0 (/8) and 255.255.255.254 (/32)
|
||||
|
||||
default gateway:
|
||||
this is the address of your router.
|
||||
|
||||
to configure a static ip during ubuntu setup, you'll need:
|
||||
- the network address in CIDR notation
|
||||
- the IP you want the device to have
|
||||
- the gateway ip
|
||||
- the DNS ip
|
||||
- optionally search domains (We'll skip this)
|
||||
|
||||
the network address in CIDR notation is probably the only difficult one.
|
||||
|
||||
compare the ipv4 address of the windows device with the subnet mask, replace the sections of the ipv4 address that are 0 on the subnet mask with 0. then add the /x from before to it.
|
||||
so lets say we have:
|
||||
192.168.15.54 - ip
|
||||
255.255.255.0 - subnet mask
|
||||
|
||||
network address:
|
||||
192.168.15.0/24
|
||||
|
||||
this actually means that you can only use addresses that are 192.168.15.x, but x can be anything from 1 to 254 (0 is the network, 255 is the broadcast address)
|
||||
|
||||
now that you have the network address, we can configure the rest.
|
||||
|
||||
for the gateway ip, simply configure the same as the gateway ip from your windows machine
|
||||
|
||||
for the DNS, configure 86.54.11.13 if you want to use joinDNS4eu, 1.1.1.1 if you want to use cloudflare or 8.8.8.8 if you want to use google DNS.
|
||||
|
||||
you can configure multiple DNS servers by separating them with comma's (like this: 8.8.8.8,8.8.4.4), the first DNS server will be prioritized.
|
||||
|
||||
|
||||
for the system's IP, you can technically pick anything within the network range we set before.
|
||||
It is recommended to pick something high so it doesn't accidentally get reserved by your DHCP service (Which you likely have for all of the devices that do not have an address manually configured).
|
||||
|
||||
i'd recommend just taking your gateway IP and replacing the last quarter with 250.
|
||||
|
||||
|
||||
## ubuntu storage configuration
|
||||
for the storage, it'll likely try to not use your whole drive, make sure to read through *the entire menu*, you only need to increase the amount of space used up by the LV to encompass the entire drive (i tend to just add a bunch of 1s at the start of the entry, which will then automatically set it to its cap)
|
||||
|
||||
|
||||
continue through the menu until the software installs, then reboot and take out the flash drive.
|
||||
|
||||
## router port-forwarding
|
||||
you will also have to do some port-forwarding on your router. if you have an ISP-provided router, this should be either very straight-forward, or you'll have to ask your ISP for help. With aftermarket routers, follow a guide online.
|
||||
|
||||
you will need to forward all of the following ports to your ubuntu machine:
|
||||
|
||||
port 80 - 80 (http web traffic)
|
||||
|
||||
port 443 - 443 (https encrypted web traffic)
|
||||
|
||||
port 51820 - 51820 (wireguard VPN)
|
||||
|
||||
port 53 - 53 (DNS)
|
||||
|
||||
port 53 is only needed if you want users outside of your network to have access to the pihole DNS. this is important if you're using a non-public hostname and want users to be able to connect without using a VPN.
|
||||
|
||||
ports 80 and 443 only need to be forwarded if you want your websites to be available outside of your local network, if you only forward port 51820, you will still be able to access everything internally and you'll be able to access everything externally when you use a VPN.
|
||||
|
||||
## DNS records
|
||||
if you are using a public DNS, you will need to add the following two records:
|
||||
|
||||
name | type | value
|
||||
|
||||
@ | A | <insert_your_public_ip_here>
|
||||
|
||||
\* | CNAME | @
|
||||
|
||||
|
||||
## Running the script
|
||||
we can now start using CloudDeploy:
|
||||
|
||||
if you get an error at the start, run the following:
|
||||
|
||||
`sudo apt update && sudo apt upgrade -y && sudo apt install git curl`
|
||||
|
||||
copy the repo:
|
||||
`sudo git clone https://git.sdgcloud.nl/SDGDen/CloudDeploy.git`
|
||||
|
||||
CD into the repo:
|
||||
`cd CloudDeploy`
|
||||
|
||||
make the deploy script runable:
|
||||
`sudo chmod a+x ./deploy.sh`
|
||||
|
||||
execute the script:
|
||||
`sudo ./deploy.sh`
|
||||
|
||||
then follow the prompts on screen.
|
||||
|
||||
Once you are done, check the post-install.txt file that was placed in your home directory (if you were logged in as root, it may be under your root home. log in as the same user and run `cd ~` to go to your home folder)
|
||||
|
||||
when you finished the tasks in the post-install.txt file, your cloud should be fully up and running! be sure to restart it at least once.
|
||||
|
||||
|
||||
the whole install from scratch will take a bit, depending on your internet speed. However, I am confident that start-to-finish, this is a one-day project. You can start this on a saturday morning and have it done before it's time for dinner.
|
||||
|
||||
|
||||
If you struggle with downloads timing out during the script, you can run the pre-download.sh script, which pre-downloads all the containers. to do this:
|
||||
|
||||
`sudo chmod a+x ./pre-download.sh`
|
||||
|
||||
`sudo ./pre-download.sh`
|
||||
|
||||
175
gencerts.sh
Normal file
@@ -0,0 +1,175 @@
|
||||
#!/bin/bash
|
||||
# Script to generate modern self-signed certificates for Nginx Proxy Manager with OpenSSL v3 extensions
|
||||
|
||||
# Prompt for domain
|
||||
read -p "Enter the domain for the certificates (e.g., example.com): " DOMAIN
|
||||
if [ -z "$DOMAIN" ]; then
|
||||
echo "Error: Domain not provided."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Define CERTS_DIR without trailing slash
|
||||
CERTS_DIR="/opt/files/certs"
|
||||
mkdir -p "$CERTS_DIR"
|
||||
|
||||
echo "Generating OpenSSL configuration files..."
|
||||
|
||||
# Root CA Configuration
|
||||
cat > "${CERTS_DIR}/openssl_root_ca.cnf" <<EOF
|
||||
[ req ]
|
||||
default_bits = 4096
|
||||
distinguished_name = req_distinguished_name
|
||||
prompt = no
|
||||
string_mask = utf8only
|
||||
x509_extensions = v3_ca
|
||||
|
||||
[ req_distinguished_name ]
|
||||
CN = $DOMAIN Root CA
|
||||
|
||||
[ v3_ca ]
|
||||
subjectKeyIdentifier = hash
|
||||
authorityKeyIdentifier = keyid:always,issuer
|
||||
basicConstraints = critical, CA:true
|
||||
keyUsage = critical, digitalSignature, keyCertSign, cRLSign
|
||||
EOF
|
||||
|
||||
# Intermediate CA Configuration
|
||||
cat > "${CERTS_DIR}/openssl_intermediate_ca.cnf" <<EOF
|
||||
[ req ]
|
||||
default_bits = 4096
|
||||
distinguished_name = req_distinguished_name
|
||||
prompt = no
|
||||
string_mask = utf8only
|
||||
x509_extensions = v3_ca
|
||||
|
||||
[ req_distinguished_name ]
|
||||
CN = $DOMAIN Intermediate CA
|
||||
|
||||
[ v3_ca ]
|
||||
subjectKeyIdentifier = hash
|
||||
authorityKeyIdentifier = keyid:always,issuer
|
||||
basicConstraints = critical, CA:true, pathlen:0
|
||||
keyUsage = critical, digitalSignature, keyCertSign, cRLSign
|
||||
EOF
|
||||
|
||||
# Wildcard CSR Configuration (minimal, no extensions)
|
||||
cat > "${CERTS_DIR}/openssl_wildcard_csr.cnf" <<EOF
|
||||
[ req ]
|
||||
default_bits = 4096
|
||||
distinguished_name = req_distinguished_name
|
||||
prompt = no
|
||||
string_mask = utf8only
|
||||
req_extensions = v3_req
|
||||
|
||||
[ req_distinguished_name ]
|
||||
CN = *.$DOMAIN
|
||||
|
||||
[ v3_req ]
|
||||
subjectAltName = @alt_names
|
||||
|
||||
[ alt_names ]
|
||||
DNS.1 = $DOMAIN
|
||||
DNS.2 = *.$DOMAIN
|
||||
EOF
|
||||
|
||||
# Wildcard Certificate Configuration (extensions for signing)
|
||||
cat > "${CERTS_DIR}/openssl_wildcard_cert.cnf" <<EOF
|
||||
[ v3_cert ]
|
||||
subjectKeyIdentifier = hash
|
||||
authorityKeyIdentifier = keyid:always,issuer:always
|
||||
basicConstraints = CA:FALSE
|
||||
keyUsage = critical, digitalSignature, keyEncipherment
|
||||
extendedKeyUsage = serverAuth
|
||||
subjectAltName = @alt_names
|
||||
|
||||
[ alt_names ]
|
||||
DNS.1 = $DOMAIN
|
||||
DNS.2 = *.$DOMAIN
|
||||
EOF
|
||||
|
||||
echo "Configuration files generated."
|
||||
|
||||
# Function to generate root CA
|
||||
generate_root_ca() {
|
||||
echo "Generating Root CA..."
|
||||
openssl genrsa -out "${CERTS_DIR}/rootCA.key" 4096
|
||||
echo "Root CA key generated."
|
||||
openssl req -x509 -new -nodes -key "${CERTS_DIR}/rootCA.key" \
|
||||
-sha256 -days 3650 -out "${CERTS_DIR}/rootCA.crt" \
|
||||
-config "${CERTS_DIR}/openssl_root_ca.cnf" -extensions v3_ca
|
||||
echo "Root CA certificate generated."
|
||||
}
|
||||
|
||||
# Function to generate intermediate CA
|
||||
generate_intermediate_ca() {
|
||||
echo "Generating Intermediate CA..."
|
||||
openssl genrsa -out "${CERTS_DIR}/intermediateCA.key" 4096
|
||||
echo "Intermediate CA key generated."
|
||||
openssl req -new -key "${CERTS_DIR}/intermediateCA.key" \
|
||||
-out "${CERTS_DIR}/intermediateCA.csr" \
|
||||
-config "${CERTS_DIR}/openssl_intermediate_ca.cnf"
|
||||
echo "Intermediate CA CSR generated."
|
||||
openssl x509 -req -in "${CERTS_DIR}/intermediateCA.csr" \
|
||||
-CA "${CERTS_DIR}/rootCA.crt" -CAkey "${CERTS_DIR}/rootCA.key" \
|
||||
-CAcreateserial -out "${CERTS_DIR}/intermediateCA.crt" \
|
||||
-days 3650 -sha256 -extfile "${CERTS_DIR}/openssl_intermediate_ca.cnf" \
|
||||
-extensions v3_ca
|
||||
echo "Intermediate CA certificate generated and signed with Root CA."
|
||||
}
|
||||
|
||||
# Function to generate wildcard certificate
|
||||
generate_wildcard_cert() {
|
||||
echo "Generating Wildcard Certificate..."
|
||||
openssl genrsa -out "${CERTS_DIR}/wildcard.key" 4096
|
||||
echo "Wildcard key generated."
|
||||
openssl req -new -key "${CERTS_DIR}/wildcard.key" \
|
||||
-out "${CERTS_DIR}/wildcard.csr" \
|
||||
-config "${CERTS_DIR}/openssl_wildcard_csr.cnf"
|
||||
echo "Wildcard CSR generated."
|
||||
openssl x509 -req -in "${CERTS_DIR}/wildcard.csr" \
|
||||
-CA "${CERTS_DIR}/intermediateCA.crt" -CAkey "${CERTS_DIR}/intermediateCA.key" \
|
||||
-CAcreateserial -out "${CERTS_DIR}/wildcard.crt" \
|
||||
-days 3650 -sha256 -extfile "${CERTS_DIR}/openssl_wildcard_cert.cnf" \
|
||||
-extensions v3_cert
|
||||
echo "Wildcard certificate generated and signed with Intermediate CA."
|
||||
}
|
||||
|
||||
# Function to export certificates for cross-platform compatibility
|
||||
export_certs() {
|
||||
echo "Exporting certificates for cross-platform compatibility..."
|
||||
# Export root CA to .pfx (Windows)
|
||||
openssl pkcs12 -export -out "${CERTS_DIR}/rootCA.pfx" \
|
||||
-inkey "${CERTS_DIR}/rootCA.key" -in "${CERTS_DIR}/rootCA.crt" -passout pass:
|
||||
echo "Root CA PFX exported."
|
||||
# Export intermediate CA to .pfx (Windows)
|
||||
openssl pkcs12 -export -out "${CERTS_DIR}/intermediateCA.pfx" \
|
||||
-inkey "${CERTS_DIR}/intermediateCA.key" -in "${CERTS_DIR}/intermediateCA.crt" -passout pass:
|
||||
echo "Intermediate CA PFX exported."
|
||||
# Export wildcard cert to .pfx (Windows)
|
||||
openssl pkcs12 -export -out "${CERTS_DIR}/wildcard.pfx" \
|
||||
-inkey "${CERTS_DIR}/wildcard.key" -in "${CERTS_DIR}/wildcard.crt" -passout pass:
|
||||
echo "Wildcard PFX exported."
|
||||
# Export root CA to .p12 (Cross-platform)
|
||||
openssl pkcs12 -export -out "${CERTS_DIR}/rootCA.p12" \
|
||||
-inkey "${CERTS_DIR}/rootCA.key" -in "${CERTS_DIR}/rootCA.crt" -passout pass:
|
||||
echo "Root CA P12 exported."
|
||||
# Export intermediate CA to .p12 (Cross-platform)
|
||||
openssl pkcs12 -export -out "${CERTS_DIR}/intermediateCA.p12" \
|
||||
-inkey "${CERTS_DIR}/intermediateCA.key" -in "${CERTS_DIR}/intermediateCA.crt" -passout pass:
|
||||
echo "Intermediate CA P12 exported."
|
||||
# Export wildcard cert to .p12 (Cross-platform)
|
||||
openssl pkcs12 -export -out "${CERTS_DIR}/wildcard.p12" \
|
||||
-inkey "${CERTS_DIR}/wildcard.key" -in "${CERTS_DIR}/wildcard.crt" -passout pass:
|
||||
echo "Wildcard P12 exported."
|
||||
}
|
||||
|
||||
# Main script execution
|
||||
generate_root_ca
|
||||
generate_intermediate_ca
|
||||
generate_wildcard_cert
|
||||
export_certs
|
||||
|
||||
echo "Certificates generated and saved in ${CERTS_DIR}:"
|
||||
echo "- Root CA: rootCA.crt, rootCA.key, rootCA.pfx, rootCA.p12"
|
||||
echo "- Intermediate CA: intermediateCA.crt, intermediateCA.key, intermediateCA.pfx, intermediateCA.p12"
|
||||
echo "- Wildcard: wildcard.crt, wildcard.key, wildcard.pfx, wildcard.p12"
|
||||
68
pre-download.sh
Normal file
@@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Ensure script is run as root (required for apt + /etc)
|
||||
if [[ "$EUID" -ne 0 ]]; then
|
||||
echo "Please run as root (or use sudo)." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#set script directory
|
||||
scriptdir="$(dirname "$(realpath "$0")")"
|
||||
|
||||
# Capture the start time (Unix timestamp)
|
||||
START_TIME=$(date +%s)
|
||||
|
||||
echo "Updating apt and installing prerequisites..."
|
||||
apt update
|
||||
apt install -y ca-certificates curl git openssl curl gawk coreutils grep jq sqlite3 iso-codes
|
||||
|
||||
echo "Setting up Docker GPG key..."
|
||||
install -m 0755 -d /etc/apt/keyrings
|
||||
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
|
||||
-o /etc/apt/keyrings/docker.asc
|
||||
chmod a+r /etc/apt/keyrings/docker.asc
|
||||
|
||||
echo "Adding Docker apt repository..."
|
||||
. /etc/os-release
|
||||
|
||||
cat > /etc/apt/sources.list.d/docker.sources <<EOF
|
||||
Types: deb
|
||||
URIs: https://download.docker.com/linux/ubuntu
|
||||
Suites: ${UBUNTU_CODENAME:-$VERSION_CODENAME}
|
||||
Components: stable
|
||||
Signed-By: /etc/apt/keyrings/docker.asc
|
||||
EOF
|
||||
|
||||
echo "Updating apt and installing Docker..."
|
||||
apt update
|
||||
apt install -y \
|
||||
docker-ce \
|
||||
docker-ce-cli \
|
||||
containerd.io \
|
||||
docker-buildx-plugin \
|
||||
docker-compose-plugin
|
||||
|
||||
echo "Docker installation complete."
|
||||
docker --version
|
||||
|
||||
|
||||
docker pull lscr.io/linuxserver/bookstack:latest
|
||||
docker pull lscr.io/linuxserver/mariadb:latest
|
||||
docker pull filebrowser/filebrowser
|
||||
docker pull ghcr.io/c4illin/convertx
|
||||
docker pull lscr.io/linuxserver/heimdall:latest
|
||||
docker pull amir20/dozzle:latest
|
||||
docker pull corentinth/it-tools:latest
|
||||
docker pull jellyfin/jellyfin
|
||||
docker pull louislam/uptime-kuma:2
|
||||
docker pull jc21/nginx-proxy-manager:latest
|
||||
docker pull onlyoffice/documentserver
|
||||
docker pull owncloud/server:latest
|
||||
docker pull mariadb:10.11
|
||||
docker pull redis:6
|
||||
docker pull pihole/pihole:latest
|
||||
docker pull lscr.io/linuxserver/nginx:latest
|
||||
docker pull vaultwarden/server:latest
|
||||
docker pull weejewel/wg-easy
|
||||
docker pull louislam/dockge:1
|
||||
79
prepdb.sh
Normal file
@@ -0,0 +1,79 @@
|
||||
# sqlite db replace function
|
||||
replace_in_sqlite_db() {
|
||||
local DB_PATH="$1"
|
||||
local OLD_STRING="$2"
|
||||
local NEW_STRING="$3"
|
||||
|
||||
# Check if the database file exists
|
||||
if [ ! -f "$DB_PATH" ]; then
|
||||
echo "Error: Database file '$DB_PATH' does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Starting replacement of '$OLD_STRING' with '$NEW_STRING' in '$DB_PATH'..."
|
||||
|
||||
# Create a backup of the original database
|
||||
local BACKUP_PATH="${DB_PATH}.bak"
|
||||
cp "$DB_PATH" "$BACKUP_PATH"
|
||||
|
||||
# Escape single quotes for SQL
|
||||
local OLD_STRING_ESC=$(printf '%s\n' "$OLD_STRING" | sed "s/'/''/g")
|
||||
local NEW_STRING_ESC=$(printf '%s\n' "$NEW_STRING" | sed "s/'/''/g")
|
||||
|
||||
# Get a list of all tables in the database
|
||||
local TABLES
|
||||
TABLES=$(sqlite3 "$DB_PATH" ".tables")
|
||||
|
||||
# Loop through each table
|
||||
for TABLE in $TABLES; do
|
||||
echo "Processing table: $TABLE"
|
||||
|
||||
# Escape table name if it's a reserved keyword
|
||||
local ESCAPED_TABLE
|
||||
if [[ "$TABLE" =~ ^(index|group|order|table|view|database|schema|trigger|transaction|commit|rollback|savepoint|release|alter|create|drop|insert|update|delete|select|from|where|join|union|intersect|except|limit|offset|order|by|group|having|as|with|replace|cast|case|when|then|else|end|and|or|not|is|null|between|in|like|glob|match|regexp|collate|exists|unique|primary|key|foreign|references|check|constraint|default|collate|asc|desc|on|using|natural|left|right|full|outer|cross|inner)$ ]]; then
|
||||
ESCAPED_TABLE="\"$TABLE\""
|
||||
else
|
||||
ESCAPED_TABLE="$TABLE"
|
||||
fi
|
||||
|
||||
# Get a list of all non-BLOB columns in the table
|
||||
sqlite3 "$DB_PATH" "PRAGMA table_info($ESCAPED_TABLE);" 2>/dev/null | awk -F'|' '
|
||||
{
|
||||
if ($3 != "BLOB") {
|
||||
print $2
|
||||
}
|
||||
}' | while read -r COLUMN; do
|
||||
if [ -n "$COLUMN" ]; then
|
||||
echo " Processing column: $COLUMN"
|
||||
|
||||
# Escape column name if it's a reserved keyword
|
||||
local ESCAPED_COLUMN
|
||||
if [[ "$COLUMN" =~ ^(index|group|order|table|view|database|schema|trigger|transaction|commit|rollback|savepoint|release|alter|create|drop|insert|update|delete|select|from|where|join|union|intersect|except|limit|offset|order|by|group|having|as|with|replace|cast|case|when|then|else|end|and|or|not|is|null|between|in|like|glob|match|regexp|collate|exists|unique|primary|key|foreign|references|check|constraint|default|collate|asc|desc|on|using|natural|left|right|full|outer|cross|inner)$ ]]; then
|
||||
ESCAPED_COLUMN="\"$COLUMN\""
|
||||
else
|
||||
ESCAPED_COLUMN="$COLUMN"
|
||||
fi
|
||||
|
||||
# Update only rows where the column contains OLD_STRING
|
||||
# Run each update in its own connection to avoid locking issues
|
||||
sqlite3 "$DB_PATH" "
|
||||
UPDATE $ESCAPED_TABLE
|
||||
SET $ESCAPED_COLUMN = replace(CAST($ESCAPED_COLUMN AS TEXT), '$OLD_STRING_ESC', '$NEW_STRING_ESC')
|
||||
WHERE CAST($ESCAPED_COLUMN AS TEXT) LIKE '%$OLD_STRING_ESC%';
|
||||
"
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
echo "Replacement completed in '$DB_PATH'. Original database backed up to '$BACKUP_PATH'."
|
||||
}
|
||||
|
||||
#set script directory
|
||||
scriptdir="$(dirname "$(realpath "$0")")"
|
||||
|
||||
#example usage: replace_in_sqlite_db "database.sqlite" "Europe/Amsterdam" "UTC"
|
||||
cp $scriptdir/stacks/dashboard/www/app-pre.sqlite $scriptdir/stacks/dashboard/www/app.sqlite
|
||||
replace_in_sqlite_db "$scriptdir/stacks/dashboard/www/app.sqlite" "mydomain.com" "<domain>"
|
||||
replace_in_sqlite_db "$scriptdir/stacks/dashboard/www/app.sqlite" "192.168.2.132" "<localip>"
|
||||
replace_in_sqlite_db "$scriptdir/stacks/dashboard/www/app.sqlite" "blah" "<adminpass>"
|
||||
replace_in_sqlite_db "$scriptdir/stacks/dashboard/www/app.sqlite" "0.0.0.0/0" "<localip>"
|
||||
74
setup/Domainless Setup.txt
Normal file
@@ -0,0 +1,74 @@
|
||||
You can set up your cloud without purchasing a domain.
|
||||
|
||||
for this, your pihole DNS is already set up to directly point ?domain? to ?localip?
|
||||
|
||||
as long as you are connected to the pihole DNS and on the local network, you will be able to reach your cloud.
|
||||
|
||||
The VPN is set up by default to use this DNS, so you will also be able to reach your cloud when using your VPN, allowing use on the go.
|
||||
|
||||
in your router's DHCP settings, set ?localip? as the DNS server.
|
||||
|
||||
in any device with a static ip, configure its dns server to ?localip?
|
||||
|
||||
|
||||
next, you'll need to deal with HTTPS certificates on your proxy server. Because we cannot use letsencrypt, we'll have to do this ourselves. You can skip this, but that results in vaultwarden not working.
|
||||
|
||||
run the gencerts.sh script, this will generate the certs for you and put them in a folder inside browser.?domain? which should now be reachable over http
|
||||
|
||||
on ?localip?:81, log in, go to certificates > add certificate > custom
|
||||
|
||||
fill in your main domain as the Name
|
||||
|
||||
for the certificate key, use the wildcard.key file
|
||||
for the certificate, use the wildcard.crt file
|
||||
for the intermediate certificate, use the intermediate.crt file
|
||||
|
||||
|
||||
because this certificate is not backed by a public certificate authority like letsencrypt, you have to manually trust the root cert on each device you want to use the cloud on, or deal with "certificate untrusted" warnings.
|
||||
|
||||
below are guides for doing this:
|
||||
|
||||
|
||||
windows:
|
||||
|
||||
download and double-click rootCA.pfx
|
||||
select "Local Machine" and click next, password is empty.
|
||||
choose "place all certificates in the following store" and choose "Trusted Root Certification Authorities"
|
||||
click finish and confirm with "yes" if prompted.
|
||||
|
||||
macOS:
|
||||
|
||||
download and double-click rootCA.pfx
|
||||
if prompted for a password, leave it blank and click yes
|
||||
open Keychain Access (applications/utilities/keychain access)
|
||||
locate the imported rootCA.pfx certificate in the login or system keychains.
|
||||
double-click the certificate, expand the "trust" section and set "When using this certificate" to "always trust"
|
||||
|
||||
Linux:
|
||||
|
||||
download the rootCA.crt file
|
||||
copy rootCA.crt to /usr/local/share/ca-certificates/ using the following command from the directory rootCA.crt is in, or by using your file manager.
|
||||
sudo cp rootCA.crt /usr/local/share/ca-certificates/
|
||||
|
||||
then update the CA store by rebooting or running the following command:
|
||||
sudo update-ca-certificates
|
||||
|
||||
android:
|
||||
|
||||
download rootCA.crt to your device
|
||||
open settings > security > encryption & credentials > install a certificate
|
||||
select rootCA.crt and set a Name
|
||||
reboot if prompted
|
||||
|
||||
IOS:
|
||||
|
||||
download rootCA.crt to your device
|
||||
open the file in safari and tap "install"
|
||||
go to settings > general > VPN & Device management > configuration profile and install the certificate
|
||||
enable full trust in settings > general > about > certificate trust settings
|
||||
|
||||
|
||||
now that you've set your DNS correctly and trusted the cert, you should be able to visit all of your sites via https://dash.?domain?
|
||||
|
||||
the certificate is valid for 10 years, after which you can generate a new one with gencerts.sh
|
||||
|
||||
15
setup/Dynamic DNS setup.txt
Normal file
@@ -0,0 +1,15 @@
|
||||
If you have a dynamic public IP, you'll have to set up DDNS since a normal DNS only points to an ip statically, and if your ip changes, everything goes down until you update the DNS record.
|
||||
|
||||
|
||||
DDNS does this automatically.
|
||||
|
||||
select a reliable service:
|
||||
noip.com
|
||||
duckdns.org
|
||||
dyn.com
|
||||
dynv6.com
|
||||
|
||||
follow their install instructions. Generally, your router will have DDNS support.
|
||||
|
||||
If it does not, you can install a DDNS client on your server (apt install ddclient)
|
||||
|
||||
30
setup/Nginx Proxy Manager - Certificates.txt
Normal file
@@ -0,0 +1,30 @@
|
||||
# Step 1:
|
||||
go to proxy.?domain? and log in with your admin account
|
||||
|
||||
# Step 2:
|
||||
go to the "Certificates" tab and click Add Certificate > Let's Encrypt via HTTP
|
||||
|
||||
# Step 3:
|
||||
copy the contents of the "npmcertlist.txt" file into the domain names field.
|
||||
copy one line at a time if using ctrl+c/ctrl+v, be sure to press enter between each line.
|
||||
|
||||
if you make use of clickpaste (or any tool that allows you to paste by simulating keyboard input), you can use that to paste the entire list in one go
|
||||
|
||||
or you can type the entire list manually
|
||||
|
||||
# Step 4:
|
||||
hit "save" and wait.
|
||||
|
||||
# Step 5:
|
||||
go to the Hosts > proxy hosts tab and go through each of the hosts
|
||||
|
||||
# Step 6:
|
||||
repeat for each host:
|
||||
>go to the SSL tab
|
||||
>select your certificate
|
||||
>enable force SSL
|
||||
in the case of owncloud you may also want to enable HTTP/2
|
||||
then hit save.
|
||||
|
||||
once you've done this for all your sites, your entire cloud is now running with SSL encryption.
|
||||
|
||||
203
setup/Setting up extra containers - example with OpenWebUI.txt
Normal file
@@ -0,0 +1,203 @@
|
||||
|
||||
|
||||
In this document, i'll be guiding you through setting up an additional service on this cloud stack.
|
||||
I'll be using OpenWebUI as the example here. It's a frontend for interacting with various LLM APIs. we'll be setting it up with Mistral.
|
||||
|
||||
to starT: Obtain a compose.yml for the service you want.
|
||||
|
||||
most of this tutorial will happen on docker.?domain?
|
||||
|
||||
when you press "compose" in the top left, you'll see an interface with a stack name on the left, a text editor on the right and a deploy button at the top.
|
||||
|
||||
this text editor on the right is where you need to write your compose file.
|
||||
|
||||
a compose file defines the service. generally it looks a bit like this:
|
||||
|
||||
|
||||
services:
|
||||
servicename:
|
||||
image: username/imagename:versiontag
|
||||
restart: restartbehaviour (generally should be unless-stopped)
|
||||
container_name: containername
|
||||
ports:
|
||||
- externalport:internalport/protocol (for example: 1234:5678/udp forwards port 1234 on the host to port 5678 on the container for the UDP protocol)
|
||||
networks:
|
||||
- network_name
|
||||
volumes:
|
||||
- dockervolume:/path/in/container (this is for docker volumes, these need to be declared separately or pre-made using commands)
|
||||
- ./relativefolder:/path/in/container (this is for if you want the volume to mount to a folder in the same folder as the compose.yml)
|
||||
- /absolute/path:/path/in/container (this is mounting an absolute path on the host as a container path)
|
||||
privileged: false/true (privileged containers have more capabilities, most notably access to systemd, you'll rarely see this, don't use this unless the container needs it)
|
||||
user: username/userID (this allows you to configure which host user the container runs under, sharing that user's file permissions)
|
||||
environment:
|
||||
variable1: value1
|
||||
variable2: value2
|
||||
variable3: value3
|
||||
healthcheck:
|
||||
test: (defines how to run the healthcheck)
|
||||
- type (for example CMD)
|
||||
- value (for example wget)
|
||||
- arg1
|
||||
- arg2
|
||||
- arg3
|
||||
- arg4
|
||||
interval: 10s (Defines how often to run the healthcheck)
|
||||
timeout: 5s (defines how long the healthcheck waits for response)
|
||||
retries: 5 (defines how many times the healthcheck retries before marking as unhealthy)
|
||||
start_period: 30s (defines how long the container is up before healthchecks start)
|
||||
networks:
|
||||
network_name:
|
||||
external: true (this must be declared for any network that is not natively part of the stack, for example a network that was made with a command or by another compose file)
|
||||
|
||||
|
||||
this is an example compose file that contains basically everything, but most of these are optional.
|
||||
|
||||
the minimum required is:
|
||||
|
||||
services:
|
||||
servicename:
|
||||
image: username/imagename:versiontag
|
||||
|
||||
but generally, i'd recommend one of the following three based on networking needs:
|
||||
|
||||
|
||||
>option 1: port-exposed. this is used for (for example) your proxy at proxy.?domain?
|
||||
|
||||
services:
|
||||
app:
|
||||
image: my/appname:version
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- 81:81
|
||||
- 80:80
|
||||
- 443:443
|
||||
environment:
|
||||
TZ: ?timezone?
|
||||
volumes:
|
||||
- ./data:/data
|
||||
|
||||
this does not have access to the internal cross-container network, but you can reach it using ?localip?:portnumber
|
||||
|
||||
>option 2: internally networked. this is used for MOST of your services (for example, for convert.?domain?)
|
||||
|
||||
services:
|
||||
app:
|
||||
image: my/appname:version
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- dockge_default
|
||||
environment:
|
||||
TZ: ?timezone?
|
||||
volumes:
|
||||
- ./data:/data
|
||||
networks:
|
||||
dockge_default:
|
||||
external: true
|
||||
|
||||
this allows the application to communicate with other docker containers, but also means you cannot reach the container externally.
|
||||
this is good because in this deployment, Nginx proxy manager handles access to the containers.
|
||||
so the user always hits up Nginx proxy manager at ports 80 and 443 (which are forwarded), and nginx internally forwards the traffic to the container.
|
||||
this is more secure because frequently, communication from the proxy to the container is http, unencrypted.
|
||||
it also means that there's no way to bypass any security measures you use in nginx proxy manager (such as access lists or third-party auth)
|
||||
|
||||
>option 3: hybrid. this is best for services that do other things they need ports for alongside serving web pages (for example, a minecraft server that also has a web interface)
|
||||
|
||||
services:
|
||||
app:
|
||||
image: my/appname:version
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- 81:81
|
||||
- 80:80
|
||||
- 443:443
|
||||
networks:
|
||||
- dockge_default
|
||||
environment:
|
||||
TZ: ?timezone?
|
||||
volumes:
|
||||
- ./data:/data
|
||||
networks:
|
||||
dockge_default
|
||||
external: true
|
||||
|
||||
this allows you to both access a port externally AND access another port internally via nginx.
|
||||
this is done for wireguard. the container has two ports: 51820 and 51821. 51820 is the port the VPN itself communicates on, so it needs to be publicly exposed and forwarded.
|
||||
51821 is the web admin portal port. we want to protect the admin portal so we did not forward this, instead it's internally forwarded using nginx, meaning we can ensure our admin access list applies.
|
||||
|
||||
|
||||
for OpenWebUI, we've provided a compose.yml file. to host any other service, simply get an example compose file for it or a docker run command.
|
||||
example docker run command:
|
||||
docker run -d -p 3000:8080 -v open-webui:/app/backend/data --name open-webui ghcr.io/open-webui/open-webui:main
|
||||
|
||||
you can turn these into compose files with dockge by going to "Home" (top right) and pasting the command into the docker run section.
|
||||
|
||||
the above docker run command maps to the following compose file:
|
||||
services:
|
||||
open-webui:
|
||||
ports:
|
||||
- 3000:8080
|
||||
volumes:
|
||||
- open-webui:/app/backend/data
|
||||
container_name: open-webui
|
||||
image: ghcr.io/open-webui/open-webui:main
|
||||
volumes:
|
||||
open-webui:
|
||||
external: true
|
||||
name: open-webui
|
||||
networks: {}
|
||||
|
||||
|
||||
AVOID ANY COMPOSE FILE WITH BUILD IN IT. this requires you to know how to use docker build, and tends to not work via dockge unless you manually clone the whole repo into /opt/stacks
|
||||
|
||||
now that you've found your compose file example, paste it into dockge in the compose UI and edit it.
|
||||
|
||||
if the service only provides a web page, remember the internal port (for example, for openwebui it's 8080) and replace ports: with networks:
|
||||
|
||||
put the service on the dockge_default internal network.
|
||||
|
||||
also make sure all volumes are relative volumes (starting with ./), so they appear in the stacks directory and you can access them via filebrowser
|
||||
|
||||
be sure to read the documentation for the compose image you're using to verify which environment variables you need to set.
|
||||
|
||||
in the case of our pre-provided compose.yml, you'll need to set two keys: the mistral API key and the webUI secret key.
|
||||
|
||||
the secret key can just be randomly generated.
|
||||
|
||||
|
||||
for mistral, head to https://console.mistral.ai/home
|
||||
make an account if you haven't already and make sure to request the free tier API
|
||||
|
||||
go to the API keys menu, make a key and paste that key into your compose.yml
|
||||
|
||||
|
||||
once you're done, you can press "Deploy" on your service.
|
||||
|
||||
|
||||
your service is now up, but it is not accessible.
|
||||
|
||||
for that, we need to first configure your proxy at proxy.?domain?
|
||||
|
||||
first, determine which subdomain you want to use, in our case we'll be using llm.?domain?
|
||||
|
||||
verify that you have a certificate that includes this subdomain under the certificates tab.
|
||||
|
||||
if you do not, make one. it's fine if this certificate is a separate certificate from the others. We did already include llm.?domain? into the list of domains for the original cert.
|
||||
|
||||
then go to hosts > proxy hosts and make a new proxy host.
|
||||
|
||||
fill in your domain name at the top.
|
||||
for forward hostname, fill in the container name of your new service. in our case this is "openwebui"
|
||||
for port, fill in the internal port from the compose file if it came with one, or google what the default port is.
|
||||
|
||||
in our case it's 8080 for the forward port.
|
||||
|
||||
enable any access list if desired, turn on websockets support and enable the SSL certificate with "force SSL" in the SSL tab.
|
||||
|
||||
|
||||
now go to your configured subdomain (in our case llm.?domain?) and follow any post-install configuration. generally, the service will guide you through it.
|
||||
|
||||
|
||||
congrats! you've brought up an additional service.
|
||||
|
||||
you can do this for any service you can find a docker compose file for. I'd recommend starting simple though.
|
||||
|
||||
27
setup/Uptime Kuma - monitoring.txt
Normal file
@@ -0,0 +1,27 @@
|
||||
# Step 1:
|
||||
head to status.?domain? and log in.
|
||||
|
||||
# Step 2:
|
||||
click on "Add New Monitor"
|
||||
|
||||
# Step 2.5 (optional):
|
||||
Set monitor type to "Group", friendly name to the group name and retries to 10.
|
||||
repeat this for any groups you want, for example: Frontend and Backend
|
||||
|
||||
# Step 3:
|
||||
use the following settings:
|
||||
type: HTTP(s)
|
||||
Friendly Name: Name of your service (for example: Cloud)
|
||||
url: the URL for the site (for example: https://cloud.?domain?)
|
||||
Retries: 10
|
||||
certificate expiry notification: on
|
||||
cachebuster: on
|
||||
group: optionally set this to the group you want
|
||||
|
||||
leave all the other settings as default
|
||||
|
||||
# Step 4:
|
||||
repeat step 3 for every service, for an easy list of URLs, go to proxy.?domain? and log in, you can see the list of proxy hosts which is also all of your URLs.
|
||||
|
||||
# Step 5 (optional):
|
||||
make a status page, instructions in Uptime Kuma - status page.txt
|
||||
14
setup/Uptime Kuma - status page.txt
Normal file
@@ -0,0 +1,14 @@
|
||||
# Step 1:
|
||||
log in to status.?domain and click on "Status Pages" in the top right.
|
||||
|
||||
# Step 2:
|
||||
make a new status page, Name it whatever you want and use slug "default"
|
||||
|
||||
# Step 3: add all of the monitors you want to the page.
|
||||
|
||||
# step 4: add a description if you'd like.
|
||||
|
||||
|
||||
this status page is available at status.?domain?/status
|
||||
|
||||
any other status pages you make are available at status.?domain?/status/<slug>
|
||||
19
setup/compose.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
services:
|
||||
openwebui:
|
||||
container_name: openwebui
|
||||
restart: always
|
||||
networks:
|
||||
- dockge_default
|
||||
volumes:
|
||||
- ./data:/app/backend/data
|
||||
environment:
|
||||
- TZ=?timezone?
|
||||
- OPENAI_API_BASE=https://api.mistral.ai/v1
|
||||
- OPENAI_API_KEY=<YOUR_MISTRAL_KEY_HERE>
|
||||
- WEB_NAME=OpenWebUI
|
||||
- AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST=30
|
||||
- WEBUI_SECRET_KEY=<RANDOM_SECRET_KEY_HERE>
|
||||
image: ghcr.io/open-webui/open-webui:main
|
||||
networks:
|
||||
dockge_default:
|
||||
external: true
|
||||
@@ -0,0 +1,33 @@
|
||||
services:
|
||||
bookstack:
|
||||
image: lscr.io/linuxserver/bookstack:latest
|
||||
container_name: bookstack
|
||||
environment:
|
||||
TZ: ?timezone?
|
||||
APP_URL: https://docs.?domain?
|
||||
APP_KEY: base64:?bookstackkey?
|
||||
DB_HOST: bookstack_db
|
||||
DB_PORT: 3306
|
||||
DB_DATABASE: bookstack
|
||||
DB_USERNAME: bookstack
|
||||
DB_PASSWORD: ?bookstackdbpass?
|
||||
volumes:
|
||||
- ./config:/config
|
||||
networks:
|
||||
- dockge_default
|
||||
restart: unless-stopped
|
||||
bookstack_db:
|
||||
image: lscr.io/linuxserver/mariadb:latest
|
||||
container_name: bookstack_db
|
||||
networks:
|
||||
- dockge_default
|
||||
environment:
|
||||
TZ: ?timezone?
|
||||
MYSQL_ROOT_PASSWORD: ?bookstackdbrootpass?
|
||||
MYSQL_DATABASE: bookstack
|
||||
MYSQL_USER: bookstack
|
||||
MYSQL_PASSWORD: ?bookstackdbpass?
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
dockge_default:
|
||||
external: true
|
||||
@@ -0,0 +1,18 @@
|
||||
services:
|
||||
browser:
|
||||
image: filebrowser/filebrowser
|
||||
privileged: true
|
||||
container_name: browser
|
||||
user: root
|
||||
networks:
|
||||
- dockge_default
|
||||
volumes:
|
||||
- /opt/stacks:/srv/stacks
|
||||
- /opt/stacks/jellyfin/media:/srv/media
|
||||
- /opt/stacks/setup:/srv/npmcertlist
|
||||
- /opt/files:/srv/files
|
||||
- ./filebrowser.db:/database.db
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
dockge_default:
|
||||
external: true
|
||||
@@ -0,0 +1,17 @@
|
||||
services:
|
||||
convertx:
|
||||
image: ghcr.io/c4illin/convertx
|
||||
container_name: convertx
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- dockge_default
|
||||
environment:
|
||||
JWT_SECRET: ?convertxJWT?
|
||||
HTTP_ALLOWED: true
|
||||
ALLOW_UNAUTHENTICATED: true
|
||||
ACCOUNT_REGISTRATION: false
|
||||
volumes:
|
||||
- ./data:/app/data
|
||||
networks:
|
||||
dockge_default:
|
||||
external: true
|
||||
@@ -0,0 +1,18 @@
|
||||
services:
|
||||
dashboard:
|
||||
image: lscr.io/linuxserver/heimdall:latest
|
||||
container_name: dashboard
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=?timezone?
|
||||
- ALLOW_INTERNAL_REQUESTS=false #optional
|
||||
- APP_NAME=Home
|
||||
volumes:
|
||||
- ./config:/config
|
||||
networks:
|
||||
- dockge_default
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
dockge_default:
|
||||
external: true
|
||||
69
stacks/dashboard/config/www/.env
Normal file
@@ -0,0 +1,69 @@
|
||||
APP_NAME=Heimdall
|
||||
APP_ENV=local
|
||||
APP_KEY=base64:iovIUyf+fbX/1gbhrxHIr/58SLI1F3u/GGVd60r4WpQ=
|
||||
APP_DEBUG=false
|
||||
APP_URL=http://localhost
|
||||
|
||||
APP_LOCALE=en
|
||||
APP_FALLBACK_LOCALE=en
|
||||
APP_FAKER_LOCALE=en_US
|
||||
APP_MAINTENANCE_DRIVER=file
|
||||
APP_MAINTENANCE_STORE=database
|
||||
BCRYPT_ROUNDS=12
|
||||
|
||||
LOG_CHANNEL=daily
|
||||
LOG_STACK=single
|
||||
|
||||
DB_CONNECTION=sqlite
|
||||
DB_DATABASE=app.sqlite
|
||||
|
||||
#DB_CONNECTION=<mysql | pgsql>
|
||||
#DB_HOST=<hostname | ip>
|
||||
#DB_PORT=<port number>
|
||||
#DB_DATABASE=<database>
|
||||
#DB_USERNAME=<user>
|
||||
#DB_PASSWORD=<password>
|
||||
|
||||
BROADCAST_CONNECTION=log
|
||||
CACHE_STORE=file
|
||||
QUEUE_CONNECTION=sync
|
||||
SESSION_DRIVER=file
|
||||
SESSION_LIFETIME=120
|
||||
SESSION_ENCRYPT=false
|
||||
SESSION_PATH=/
|
||||
SESSION_DOMAIN=null
|
||||
QUEUE_DRIVER=database
|
||||
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
MAIL_MAILER=smtp
|
||||
MAIL_HOST=smtp.mailtrap.io
|
||||
MAIL_PORT=2525
|
||||
MAIL_USERNAME=null
|
||||
MAIL_PASSWORD=null
|
||||
MAIL_ENCRYPTION=null
|
||||
MAIL_FROM_ADDRESS=null
|
||||
MAIL_FROM_NAME="${APP_NAME}"
|
||||
|
||||
AWS_ACCESS_KEY_ID=
|
||||
AWS_SECRET_ACCESS_KEY=
|
||||
AWS_DEFAULT_REGION=us-east-1
|
||||
AWS_BUCKET=
|
||||
|
||||
PUSHER_APP_ID=
|
||||
PUSHER_APP_KEY=
|
||||
PUSHER_APP_SECRET=
|
||||
PUSHER_APP_CLUSTER=mt1
|
||||
|
||||
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
|
||||
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
||||
|
||||
AUTH_ROLES_ENABLE=false
|
||||
AUTH_ROLES_HEADER="remote-groups"
|
||||
AUTH_ROLES_HTTP_HEADER="HTTP_REMOTE_GROUPS"
|
||||
AUTH_ROLES_ADMIN="admin"
|
||||
AUTH_ROLES_DELIMITER=","
|
||||
|
||||
ALLOW_INTERNAL_REQUESTS=false
|
||||
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace App\SupportedApps\Bookstack;
|
||||
|
||||
class Bookstack extends \App\SupportedApps implements \App\EnhancedApps
|
||||
{
|
||||
public $config;
|
||||
|
||||
//protected $login_first = true; // Uncomment if api requests need to be authed first
|
||||
//protected $method = 'POST'; // Uncomment if requests to the API should be set by POST
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
//$this->jar = new \GuzzleHttp\Cookie\CookieJar; // Uncomment if cookies need to be set
|
||||
}
|
||||
|
||||
public function getHeaders()
|
||||
{
|
||||
$api_token = $this->config->api_token . ":" . $this->config->api_secret;
|
||||
|
||||
$attrs["headers"] = ["Authorization" => "Token " . $api_token];
|
||||
return $attrs;
|
||||
}
|
||||
|
||||
public function test()
|
||||
{
|
||||
$test = parent::appTest(
|
||||
$this->url("api/shelves?count=0"),
|
||||
$this->getHeaders()
|
||||
);
|
||||
echo $test->status;
|
||||
}
|
||||
|
||||
public function livestats()
|
||||
{
|
||||
$status = "inactive";
|
||||
|
||||
$attrs = $this->getHeaders();
|
||||
|
||||
$data = ["visiblestats" => []];
|
||||
|
||||
foreach ($this->config->availablestats as $stat) {
|
||||
if (!isset(self::getAvailableStats()[$stat])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$res = parent::execute(
|
||||
$this->url("api/" . $stat . "?count=0"),
|
||||
$attrs
|
||||
);
|
||||
$details = json_decode($res->getBody());
|
||||
|
||||
$newstat = new \stdClass();
|
||||
$newstat->title = self::getAvailableStats()[$stat];
|
||||
$newstat->value = isset($details->total)
|
||||
? number_format($details->total)
|
||||
: "N/A";
|
||||
|
||||
$data["visiblestats"][] = $newstat;
|
||||
}
|
||||
|
||||
return parent::getLiveStats($status, $data);
|
||||
}
|
||||
|
||||
public function url($endpoint)
|
||||
{
|
||||
$api_url =
|
||||
rtrim(parent::normaliseurl($this->config->url), "/") .
|
||||
"/" .
|
||||
ltrim($endpoint, "/");
|
||||
return $api_url;
|
||||
}
|
||||
|
||||
public static function getAvailableStats()
|
||||
{
|
||||
return [
|
||||
"shelves" => "Shelves",
|
||||
"books" => "Books",
|
||||
"chapters" => "Chapters",
|
||||
"pages" => "Pages",
|
||||
];
|
||||
}
|
||||
}
|
||||
10
stacks/dashboard/config/www/SupportedApps/Bookstack/app.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"appid": "348c49dd03dddd418929316668d2e67bf2d9ae88",
|
||||
"name": "Bookstack",
|
||||
"website": "https://www.bookstackapp.com",
|
||||
"license": "MIT License",
|
||||
"description": "BookStack is a simple, self-hosted, easy-to-use platform for organising and storing information.",
|
||||
"enhanced": true,
|
||||
"tile_background": "dark",
|
||||
"icon": "bookstack.svg"
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<h2>{{ __('app.apps.config') }} ({{ __('app.optional') }}) @include('items.enable')</h2>
|
||||
<div class="items">
|
||||
<div class="input">
|
||||
<label>{{ strtoupper(__('app.url')) }}</label>
|
||||
{!! Form::text('config[override_url]', isset($item) ? $item->getConfig()->override_url ?? null : null, ['placeholder' => __('app.apps.override'), 'id' => 'override_url', 'class' => 'form-control']) !!}
|
||||
</div>
|
||||
<div class="input">
|
||||
<label>Token ID</label>
|
||||
{!! Form::text('config[api_token]', isset($item) ? $item->getconfig()->api_token : null, ['placeholder' => 'Token ID', 'data-config' => 'api_token', 'class' => 'form-control config-item']) !!}
|
||||
</div>
|
||||
<div class="input">
|
||||
<label>Token Secret</label>
|
||||
{!! Form::text('config[api_secret]', isset($item) ? $item->getconfig()->api_secret : null, ['placeholder' => 'Token Secret', 'data-config' => 'api_secret', 'class' => 'form-control config-item']) !!}
|
||||
</div>
|
||||
<div class="input">
|
||||
<label>Stats to show</label>
|
||||
{!! Form::select('config[availablestats][]', App\SupportedApps\Bookstack\Bookstack::getAvailableStats(), isset($item) ? $item->getConfig()->availablestats ?? null : null, ['multiple' => 'multiple']) !!}
|
||||
</div>
|
||||
<div class="input">
|
||||
<button style="margin-top: 32px;" class="btn test" id="test_config">Test</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,8 @@
|
||||
<ul class="livestats">
|
||||
@foreach ($visiblestats as $stat)
|
||||
<li>
|
||||
<span class="title">{!! $stat->title !!}</span>
|
||||
<strong>{!! $stat->value !!}</strong>
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace App\SupportedApps\Dockge;
|
||||
|
||||
class Dockge extends \App\SupportedApps
|
||||
{
|
||||
}
|
||||
10
stacks/dashboard/config/www/SupportedApps/Dockge/app.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"appid": "0bafb882c9d2c034ca5333367f8ccc90f4ae85e4",
|
||||
"name": "Dockge",
|
||||
"website": "https://github.com/louislam/dockge",
|
||||
"license": "MIT License",
|
||||
"description": "A fancy, easy-to-use and reactive self-hosted docker compose.yaml stack-oriented manager.",
|
||||
"enhanced": false,
|
||||
"tile_background": "dark",
|
||||
"icon": "dockge.svg"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace App\SupportedApps\Dozzle;
|
||||
|
||||
class Dozzle extends \App\SupportedApps
|
||||
{
|
||||
}
|
||||
10
stacks/dashboard/config/www/SupportedApps/Dozzle/app.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"appid": "176d99d897dbd7c02b1a1db4142054f74a76aa47",
|
||||
"name": "Dozzle",
|
||||
"website": "https://dozzle.dev",
|
||||
"license": "MIT License",
|
||||
"description": "Dozzle is a real-time log viewer for docker containers.",
|
||||
"enhanced": false,
|
||||
"tile_background": "dark",
|
||||
"icon": "dozzle.svg"
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
namespace App\SupportedApps\FileBrowser;
|
||||
|
||||
class FileBrowser extends \App\SupportedApps implements \App\EnhancedApps
|
||||
{
|
||||
public $config;
|
||||
|
||||
//protected $login_first = true; // Uncomment if api requests need to be authed first
|
||||
//protected $method = 'POST'; // Uncomment if requests to the API should be set by POST
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
//$this->jar = new \GuzzleHttp\Cookie\CookieJar; // Uncomment if cookies need to be set
|
||||
}
|
||||
|
||||
private function getToken()
|
||||
{
|
||||
$username = $this->config->username;
|
||||
$password = $this->config->password;
|
||||
$authHeader = $this->config->authHeader;
|
||||
|
||||
$attrs = [
|
||||
"headers" => [
|
||||
"Content-Type" => "application/json"
|
||||
],
|
||||
"body" => json_encode([
|
||||
"username" => $username,
|
||||
"password" => $password
|
||||
])
|
||||
];
|
||||
if ($authHeader !== null) {
|
||||
$attrs["headers"][$authHeader] = $username;
|
||||
}
|
||||
|
||||
$res = parent::execute($this->url("api/login"), $attrs, null, "POST");
|
||||
|
||||
switch ($res->getStatusCode()) {
|
||||
case 200:
|
||||
return $res->getBody()->getContents();
|
||||
case 403:
|
||||
throw new \Exception("Invalid username/password");
|
||||
default:
|
||||
throw new \Exception("Could not connect to FileBrowser");
|
||||
}
|
||||
}
|
||||
|
||||
private function formatBytes($bytes, $precision = 2) {
|
||||
$units = array('B', 'KB', 'MB', 'GB', 'TB');
|
||||
$bytes = max($bytes, 0);
|
||||
$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
|
||||
$pow = min($pow, count($units) - 1);
|
||||
|
||||
$bytes /= pow(1024, $pow);
|
||||
|
||||
$value = round($bytes, $precision);
|
||||
$unit = $units[$pow];
|
||||
|
||||
return [
|
||||
"value" => $value,
|
||||
"unit" => $unit
|
||||
];
|
||||
}
|
||||
|
||||
public function test()
|
||||
{
|
||||
try {
|
||||
$token = $this->getToken();
|
||||
echo "Successfully communicated with the API";
|
||||
} catch (Exception $err) {
|
||||
echo $err->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
public function livestats()
|
||||
{
|
||||
$status = "inactive";
|
||||
|
||||
$token = $this->getToken();
|
||||
$attrs = [
|
||||
"headers" => [
|
||||
"X-AUTH" => $token
|
||||
],
|
||||
];
|
||||
$res = parent::execute($this->url("api/usage"), $attrs);
|
||||
$details = json_decode($res->getBody());
|
||||
|
||||
if ($details != null) {
|
||||
$data["used"] = $this->formatBytes($details->used);
|
||||
$data["total"] = $this->formatBytes($details->total);
|
||||
}
|
||||
return parent::getLiveStats($status, $data);
|
||||
}
|
||||
|
||||
public function url($endpoint)
|
||||
{
|
||||
$api_url = parent::normaliseurl($this->config->url) . $endpoint;
|
||||
|
||||
return $api_url;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"appid": "ba05dd8e070851895ee6184eb9778cfa0753a490",
|
||||
"name": "FileBrowser",
|
||||
"website": "https://github.com/filebrowser/filebrowser",
|
||||
"license": "Apache License 2.0",
|
||||
"description": "filebrowser provides a file managing interface within a specified directory and it can be used to upload, delete, preview, rename and edit your files. It allows the creation of multiple users and each user can have its own directory. It can be used as a standalone app or as a middleware.",
|
||||
"enhanced": true,
|
||||
"tile_background": "dark",
|
||||
"icon": "filebrowser.svg"
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<h2>{{ __('app.apps.config') }} ({{ __('app.optional') }}) @include('items.enable')</h2>
|
||||
<div class="items" style="flex-direction:column">
|
||||
<div style="display:flex;flex-direction:row;">
|
||||
<div class="input">
|
||||
<label>{{ strtoupper(__('app.url')) }}</label>
|
||||
{!! Form::text('config[override_url]', isset($item) ? $item->getconfig()->override_url : null, ['placeholder' => __('app.apps.override'), 'id' => 'override_url', 'class' => 'form-control']) !!}
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:flex;flex-direction:row;">
|
||||
<div class="input">
|
||||
<label>{{ __('app.apps.username') }}</label>
|
||||
{!! Form::text('config[username]', isset($item) ? $item->getconfig()->username : null, ['placeholder' => __('app.apps.username'), 'data-config' => 'username', 'class' => 'form-control config-item']) !!}
|
||||
</div>
|
||||
<div class="input">
|
||||
<label>{{ __('app.apps.password') }}</label>
|
||||
{!! Form::input('password', 'config[password]', '', ['placeholder' => __('app.apps.password'), 'data-config' => 'password', 'class' => 'form-control config-item']) !!}
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:flex;flex-direction:row;">
|
||||
<div class="input">
|
||||
<label>Proxy Header (<a href="https://filebrowser.org/configuration/authentication-method#proxy-header" target="_blank">help?</a>)</label>
|
||||
{!! Form::text('config[authHeader]', isset($item) ? $item->getconfig()->authHeader : null, ['placeholder' => 'X-My-Header', 'data-config' => 'authHeader', 'class' => 'form-control config-item']) !!}
|
||||
<small>Also fill {{ __('app.apps.username') }}</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input">
|
||||
<button style="margin-top: 32px;" class="btn test" id="test_config">Test</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,10 @@
|
||||
<ul class="livestats">
|
||||
<li>
|
||||
<span class="title">Used</span>
|
||||
<strong>{!! $used["value"] !!}<span>{!! $used["unit"] !!}</span></strong>
|
||||
</li>
|
||||
<li>
|
||||
<span class="title">Total</span>
|
||||
<strong>{!! $total["value"] !!}<span>{!! $total["unit"] !!}</span></strong>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace App\SupportedApps\ITTools;
|
||||
|
||||
class ITTools extends \App\SupportedApps
|
||||
{
|
||||
}
|
||||
10
stacks/dashboard/config/www/SupportedApps/ITTools/app.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"appid": "b5f16344632fdfe68391a2dc3816ee0edbb1813c",
|
||||
"name": "IT-Tools",
|
||||
"website": "https://it-tools.tech/",
|
||||
"license": "GNU General Public License v3.0 only",
|
||||
"description": "Useful tools for developer and people working in IT.",
|
||||
"enhanced": false,
|
||||
"tile_background": "light",
|
||||
"icon": "ittools.png"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace App\SupportedApps\JDownloader;
|
||||
|
||||
class JDownloader extends \App\SupportedApps
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"appid": "af7b37e2841d9150f6abd5a936b32a1f681d6bda",
|
||||
"name": "JDownloader",
|
||||
"website": "http://jdownloader.org",
|
||||
"license": "Creative Commons Attribution Non Commercial Share Alike 2.0 Generic",
|
||||
"description": "JDownloader is a free, open-source download management tool with a huge community of developers that makes downloading as easy and fast as it should be.",
|
||||
"enhanced": false,
|
||||
"tile_background": "dark",
|
||||
"icon": "jdownloader.png"
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace App\SupportedApps\Jellyfin;
|
||||
|
||||
class Jellyfin extends \App\SupportedApps implements \App\EnhancedApps
|
||||
{
|
||||
public $config;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
public function test()
|
||||
{
|
||||
$test = parent::appTest(
|
||||
$this->url("System/Info"),
|
||||
$this->getAttrs()
|
||||
);
|
||||
echo $test->status;
|
||||
}
|
||||
|
||||
public function livestats()
|
||||
{
|
||||
$status = "inactive";
|
||||
$res = parent::execute($this->url("Items/Counts"), $this->getAttrs());
|
||||
$result = json_decode($res->getBody());
|
||||
$details = ["visiblestats" => []];
|
||||
foreach ($this->config->availablestats as $stat) {
|
||||
$newstat = new \stdClass();
|
||||
$newstat->title = self::getAvailableStats()[$stat];
|
||||
$newstat->value = $result->{$stat};
|
||||
$details["visiblestats"][] = $newstat;
|
||||
}
|
||||
return parent::getLiveStats($status, $details);
|
||||
}
|
||||
public function url($endpoint)
|
||||
{
|
||||
$api_url = parent::normaliseurl($this->config->url) . $endpoint;
|
||||
return $api_url;
|
||||
}
|
||||
|
||||
private function getAttrs()
|
||||
{
|
||||
$authorizationHeader = "MediaBrowser " .
|
||||
"Token=\"" . urlencode($this->config->password) . "\", " .
|
||||
"Client=\"Heimdall\"";
|
||||
return [
|
||||
"headers" => [
|
||||
"Authorization" => $authorizationHeader,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public static function getAvailableStats()
|
||||
{
|
||||
return [
|
||||
"MovieCount" => "Movies",
|
||||
"SeriesCount" => "Series",
|
||||
"EpisodeCount" => "Episodes",
|
||||
"ArtistCount" => "Artists",
|
||||
"ProgramCount" => "Programs",
|
||||
"TrailerCount" => "Trailers",
|
||||
"SongCount" => "Songs",
|
||||
"AlbumCount" => "Albums",
|
||||
"MusicVideoCount" => "MusicVideos",
|
||||
"BoxSetCount" => "BoxSets",
|
||||
"BookCount" => "Books",
|
||||
"ItemCount" => "Items",
|
||||
];
|
||||
}
|
||||
}
|
||||
10
stacks/dashboard/config/www/SupportedApps/Jellyfin/app.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"appid": "3e0a7f109bd760b9474c78cb652e8c3e82669226",
|
||||
"name": "Jellyfin",
|
||||
"website": "https://jellyfin.github.io",
|
||||
"license": "GNU General Public License v2.0 only",
|
||||
"description": "Jellyfin is the Free Software Media System that puts you in control of managing and streaming your media. There are no strings attached, no premium licenses or features, and no hidden agendas.",
|
||||
"enhanced": true,
|
||||
"tile_background": "dark",
|
||||
"icon": "jellyfin.svg"
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<h2>{{ __('app.apps.config') }} ({{ __('app.optional') }}) @include('items.enable')</h2>
|
||||
<div class="items">
|
||||
<div class="input">
|
||||
<label>{{ strtoupper(__('app.url')) }}</label>
|
||||
{!! Form::text('config[override_url]', isset($item) ? $item->getconfig()->override_url : null, ['placeholder' => __('app.apps.override'), 'id' => 'override_url', 'class' => 'form-control']) !!}
|
||||
</div>
|
||||
<div class="input">
|
||||
<label>{{ __('app.apps.password') }} (secret token)</label>
|
||||
{!! Form::input('password', 'config[password]', '', ['placeholder' => __('app.apps.password'), 'data-config' => 'password', 'class' => 'form-control config-item']) !!}
|
||||
</div>
|
||||
<div class="input">
|
||||
<label>Stats to show</label>
|
||||
{!! Form::select('config[availablestats][]', App\SupportedApps\Jellyfin\Jellyfin::getAvailableStats(), isset($item) ? $item->getConfig()->availablestats ?? null : null, ['multiple' => 'multiple']) !!}
|
||||
</div>
|
||||
<div class="input">
|
||||
<button style="margin-top: 32px;" class="btn test" id="test_config">Test</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,8 @@
|
||||
<ul class="livestats">
|
||||
@foreach ($visiblestats as $stat)
|
||||
<li>
|
||||
<span class="title">{!! $stat->title !!}</span>
|
||||
<strong>{!! $stat->value !!}</strong>
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace App\SupportedApps\NginxProxyManager;
|
||||
|
||||
class NginxProxyManager extends \App\SupportedApps implements \App\EnhancedApps
|
||||
{
|
||||
public $config;
|
||||
|
||||
//protected $login_first = true; // Uncomment if api requests need to be authed first
|
||||
//protected $method = 'POST'; // Uncomment if requests to the API should be set by POST
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
//$this->jar = new \GuzzleHttp\Cookie\CookieJar; // Uncomment if cookies need to be set
|
||||
}
|
||||
|
||||
public function test()
|
||||
{
|
||||
$test = parent::appTest($this->url("api"));
|
||||
echo $test->status;
|
||||
}
|
||||
|
||||
public function livestats()
|
||||
{
|
||||
$status = "inactive";
|
||||
$auth_attrs = [
|
||||
"headers" => [
|
||||
"Accept" => "application/json",
|
||||
"Content-Type" => "application/json",
|
||||
],
|
||||
"body" => json_encode([
|
||||
"identity" => $this->config->email,
|
||||
"secret" => $this->config->password,
|
||||
]),
|
||||
];
|
||||
$auth_res = parent::execute(
|
||||
$this->url("api/tokens"),
|
||||
$auth_attrs,
|
||||
null,
|
||||
"POST"
|
||||
);
|
||||
$auth_data = json_decode($auth_res->getBody(), true);
|
||||
$token = $auth_data["token"];
|
||||
|
||||
$attrs = [
|
||||
"headers" => [
|
||||
"Accept" => "application/json",
|
||||
"Authorization" => "Bearer " . $token,
|
||||
],
|
||||
];
|
||||
$res = parent::execute($this->url("api/reports/hosts"), $attrs);
|
||||
$data = json_decode($res->getBody(), true);
|
||||
|
||||
return parent::getLiveStats($status, $data);
|
||||
}
|
||||
public function url($endpoint)
|
||||
{
|
||||
$api_url = parent::normaliseurl($this->config->url) . $endpoint;
|
||||
return $api_url;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"appid": "cbfad988a16a9fbcc1812bc206afcc1f73dd36de",
|
||||
"name": "Nginx Proxy Manager",
|
||||
"website": "https://nginxproxymanager.jc21.com",
|
||||
"license": "MIT License",
|
||||
"description": "This project comes as a pre-built docker image that enables you to easily forward to your websites running at home or otherwise, including free SSL, without having to know too much about Nginx or Letsencrypt.",
|
||||
"enhanced": true,
|
||||
"tile_background": "light",
|
||||
"icon": "nginxproxymanager.png"
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<h2>{{ __('app.apps.config') }} ({{ __('app.optional') }}) @include('items.enable')</h2>
|
||||
<div class="items">
|
||||
<div class="input">
|
||||
<label>{{ strtoupper(__('app.url')) }}</label>
|
||||
{!! Form::text('config[override_url]', isset($item) ? $item->getconfig()->override_url : null, ['placeholder' => __('app.apps.override'), 'id' => 'override_url', 'class' => 'form-control']) !!}
|
||||
</div>
|
||||
<div class="input">
|
||||
<label>Email address</label>
|
||||
{!! Form::text('config[email]', isset($item) ? $item->getconfig()->email : null, ['placeholder' => __('Email address'), 'data-config' => 'email', 'class' => 'form-control config-item']) !!}
|
||||
</div>
|
||||
<div class="input">
|
||||
<label>{{ __('app.apps.password') }}</label>
|
||||
{!! Form::input('password', 'config[password]', '', ['placeholder' => __('app.apps.password'), 'data-config' => 'password', 'class' => 'form-control config-item']) !!}
|
||||
</div>
|
||||
<div class="input">
|
||||
<button style="margin-top: 32px;" class="btn test" id="test_config">Test</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,10 @@
|
||||
<ul class="livestats">
|
||||
<li>
|
||||
<span class="title">Proxy Hosts</span>
|
||||
<strong>{!! $proxy !!}</strong>
|
||||
</li>
|
||||
<li>
|
||||
<span class="title">Redirection Hosts</span>
|
||||
<strong>{!! $redirection !!}</strong>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace App\SupportedApps\OnlyOffice;
|
||||
|
||||
class OnlyOffice extends \App\SupportedApps
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"appid": "fc4e407d69510b855b678aa4fba6083fbbfc5383",
|
||||
"name": "OnlyOffice",
|
||||
"website": "https://www.onlyoffice.com",
|
||||
"license": "GNU Affero General Public License v3.0 or later",
|
||||
"description": "ONLYOFFICE online editors for text documents, spreadsheets, and presentations with access to pro features and connect them to the platform of your choice with ready-to-use connectors: https://www.onlyoffice.com/download.aspx#connectors",
|
||||
"enhanced": false,
|
||||
"tile_background": "light",
|
||||
"icon": "onlyoffice.png"
|
||||
}
|
||||
184
stacks/dashboard/config/www/SupportedApps/Pihole/Pihole.php
Normal file
@@ -0,0 +1,184 @@
|
||||
<?php
|
||||
|
||||
namespace App\SupportedApps\Pihole;
|
||||
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class Pihole extends \App\SupportedApps implements \App\EnhancedApps
|
||||
{
|
||||
public $config;
|
||||
|
||||
//protected $login_first = true; // Uncomment if api requests need to be authed first
|
||||
//protected $method = 'POST'; // Uncomment if requests to the API should be set by POST
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->jar = new \GuzzleHttp\Cookie\CookieJar(); // Uncomment if cookies need to be set
|
||||
}
|
||||
|
||||
public function test()
|
||||
{
|
||||
$version = $this->config->version;
|
||||
|
||||
if ($version == 5) {
|
||||
$test = parent::appTest($this->url("api.php?summaryRaw"));
|
||||
echo $test->status;
|
||||
}
|
||||
if ($version == 6) {
|
||||
$test = $this->getInfo();
|
||||
if ($test["valid"]) {
|
||||
echo "Successfully communicated with the API";
|
||||
} else {
|
||||
echo "Error while communicating with the API: " . $test["message"];
|
||||
}
|
||||
}
|
||||
}
|
||||
public function livestats()
|
||||
{
|
||||
$data = [];
|
||||
$status = "inactive";
|
||||
$version = $this->config->version;
|
||||
|
||||
if ($version == 5) {
|
||||
$res = parent::execute($this->url("api.php?summaryRaw"));
|
||||
$details = json_decode($res->getBody());
|
||||
if ($details) {
|
||||
$data["ads_blocked"] = number_format(
|
||||
$details->ads_blocked_today
|
||||
);
|
||||
$data["ads_percentage"] = number_format(
|
||||
$details->ads_percentage_today,
|
||||
1
|
||||
);
|
||||
|
||||
$status = "active";
|
||||
}
|
||||
}
|
||||
|
||||
if ($version == 6) {
|
||||
$results = $this->getInfo();
|
||||
|
||||
if ($results["valid"]) {
|
||||
$data["ads_blocked"] = $results["queries"];
|
||||
$data["ads_percentage"] = $results["percent"];
|
||||
|
||||
$status = "active";
|
||||
}
|
||||
}
|
||||
return parent::getLiveStats($status, $data);
|
||||
}
|
||||
|
||||
public function url($endpoint)
|
||||
{
|
||||
$version = $this->config->version;
|
||||
if ($version == 5) {
|
||||
$apikey = $this->config->apikey;
|
||||
$api_url = parent::normaliseurl($this->config->url) . $endpoint;
|
||||
|
||||
if ($apikey) {
|
||||
$api_url .= "&auth=" . $apikey;
|
||||
}
|
||||
}
|
||||
if ($version == 6) {
|
||||
$api_url = parent::normaliseurl($this->config->url) . $endpoint;
|
||||
}
|
||||
return $api_url;
|
||||
}
|
||||
|
||||
public function getInfo()
|
||||
{
|
||||
$ignoreTls = $this->getConfigValue("ignore_tls", false);
|
||||
if ($ignoreTls) {
|
||||
$attrs = [
|
||||
"body" => json_encode(['password' => $this->config->apikey]),
|
||||
"cookies" => $this->jar,
|
||||
"verify" => false,
|
||||
"headers" => [
|
||||
"Content-Type" => "application/json",
|
||||
"Accept" => "application/json",
|
||||
],
|
||||
];
|
||||
$attrsid["verify"] = false;
|
||||
} else {
|
||||
$attrs = [
|
||||
"body" => json_encode(['password' => $this->config->apikey]),
|
||||
"cookies" => $this->jar,
|
||||
"headers" => [
|
||||
"Content-Type" => "application/json",
|
||||
"Accept" => "application/json",
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
// Create session and retrieve data
|
||||
$response = parent::execute($this->url("api/auth"), $attrs, null, "POST");
|
||||
$auth = json_decode($response->getBody());
|
||||
|
||||
if (!$auth->session->valid) {
|
||||
$data = [
|
||||
'valid' => false,
|
||||
'validity' => -1,
|
||||
'message' => $auth->session->message,
|
||||
'queries' => 0,
|
||||
'percent' => 0
|
||||
];
|
||||
return $data;
|
||||
}
|
||||
|
||||
if ($ignoreTls) {
|
||||
$attrsid = [
|
||||
"body" => json_encode(['sid' => $auth->session->sid]),
|
||||
"cookies" => $this->jar,
|
||||
"verify" => false,
|
||||
"headers" => [
|
||||
"Content-Type" => "application/json",
|
||||
"Accept" => "application/json",
|
||||
],
|
||||
];
|
||||
} else {
|
||||
$attrsid = [
|
||||
"body" => json_encode(['sid' => $auth->session->sid]),
|
||||
"cookies" => $this->jar,
|
||||
"headers" => [
|
||||
"Content-Type" => "application/json",
|
||||
"Accept" => "application/json",
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
// Get queries data
|
||||
$responsesummary = parent::execute($this->url("api/stats/summary"), $attrsid, null, "GET");
|
||||
$datasummary = json_decode($responsesummary->getBody());
|
||||
|
||||
// After retrieving the data the session is closed to declutter
|
||||
parent::execute($this->url("api/auth"), $attrsid, null, "DELETE");
|
||||
|
||||
// Extract data from the response
|
||||
$valid = $auth->session->valid;
|
||||
$validity = $auth->session->validity;
|
||||
$message = $auth->session->message;
|
||||
|
||||
if (!$auth->session->valid) {
|
||||
$queriesblocked = 0;
|
||||
$percentblocked = 0;
|
||||
} else {
|
||||
$queriesblocked = $datasummary->queries->blocked;
|
||||
$percentblocked = round($datasummary->queries->percent_blocked, 2);
|
||||
}
|
||||
|
||||
$data = [
|
||||
'valid' => $valid,
|
||||
'validity' => $validity,
|
||||
'message' => $message,
|
||||
'queries' => $queriesblocked,
|
||||
'percent' => $percentblocked
|
||||
];
|
||||
return $data;
|
||||
}
|
||||
public function getConfigValue($key, $default = null)
|
||||
{
|
||||
return isset($this->config) && isset($this->config->$key)
|
||||
? $this->config->$key
|
||||
: $default;
|
||||
}
|
||||
}
|
||||
10
stacks/dashboard/config/www/SupportedApps/Pihole/app.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"appid": "b89920409bdce40e08ba1023480b0546061cd577",
|
||||
"name": "Pi-hole",
|
||||
"website": "https://pi-hole.net",
|
||||
"license": "European Union Public License 1.2",
|
||||
"description": "Pi-hole is a Linux network-level advertisement and internet tracker blocking application which acts as a DNS sinkhole, intended for use on a private network.",
|
||||
"enhanced": true,
|
||||
"tile_background": "dark",
|
||||
"icon": "pihole.svg"
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<h2>{{ __('app.apps.config') }} ({{ __('app.optional') }}) @include('items.enable')</h2>
|
||||
<div class="items">
|
||||
<input type="hidden" data-config="dataonly" class="config-item" name="config[dataonly]" value="1" />
|
||||
<div class="input">
|
||||
<label>{{ strtoupper(__('app.url')) }}</label>
|
||||
{!! Form::text('config[override_url]', isset($item) ? $item->getconfig()->override_url : null, ['placeholder' => __('app.apps.override'), 'id' => 'override_url', 'class' => 'form-control']) !!}
|
||||
</div>
|
||||
<div class="input">
|
||||
<label>Api Key(v5)/App Password(v6)</label>
|
||||
{!! Form::text('config[apikey]', isset($item) && property_exists($item->getconfig(), 'apikey') ? $item->getconfig()->apikey : null, ['placeholder' => __('app.apps.apikey'), 'data-config' => 'apikey', 'class' => 'form-control config-item']) !!}
|
||||
</div>
|
||||
<div class="items" style="max-width: 100px;">
|
||||
<div class="input">
|
||||
<label>Version</label>
|
||||
{!! Form::select(
|
||||
'config[version]',
|
||||
['5' => 'v5', '6' => 'v6'],
|
||||
isset($item) ? $item->getconfig()->version : null,
|
||||
['data-config' => 'version', 'class' => 'form-control config-item'],
|
||||
) !!}
|
||||
</div>
|
||||
</div>
|
||||
<div class="input" style="max-width: 150px;">
|
||||
<label>Skip TLS verification</label>
|
||||
<div class="toggleinput" style="margin-top: 26px; padding-left: 15px;">
|
||||
{!! Form::hidden('config[ignore_tls]', 0, ['class' => 'config-item', 'data-config' => 'ignore_tls']) !!}
|
||||
<label class="switch">
|
||||
<?php
|
||||
$checked = false;
|
||||
if (isset($item) && !empty($item) && isset($item->getconfig()->ignore_tls)) {
|
||||
$checked = $item->getconfig()->ignore_tls;
|
||||
}
|
||||
$set_checked = $checked ? ' checked="checked"' : '';
|
||||
?>
|
||||
<input type="checkbox" class="config-item" data-config="ignore_tls" name="config[ignore_tls]" value="1" <?php echo $set_checked; ?> />
|
||||
<span class="slider round"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input">
|
||||
<button style="margin-top: 32px;" class="btn test" id="test_config">Test</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,10 @@
|
||||
<ul class="livestats">
|
||||
<li>
|
||||
<span class="title">Queries<br />Blocked</span>
|
||||
<strong>{!! $ads_blocked !!}</strong>
|
||||
</li>
|
||||
<li>
|
||||
<span class="title">Percent<br /> Blocked</span>
|
||||
<strong>{!! $ads_percentage !!}</strong>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
namespace App\SupportedApps\UptimeKuma;
|
||||
|
||||
class UptimeKuma extends \App\SupportedApps implements \App\EnhancedApps
|
||||
{
|
||||
public $config;
|
||||
|
||||
private $mapping = [
|
||||
0 => "down",
|
||||
1 => "up",
|
||||
2 => "pending",
|
||||
3 => "maintenance",
|
||||
];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
private function getAttrs()
|
||||
{
|
||||
if (empty($this->config->apikey)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$basicAuthValue = base64_encode(":" . $this->config->apikey);
|
||||
|
||||
return [
|
||||
"headers" => [
|
||||
"Authorization" => "Basic " . $basicAuthValue,
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public function test()
|
||||
{
|
||||
|
||||
$test = parent::appTest($this->url("metrics"), $this->getAttrs());
|
||||
echo $test->status;
|
||||
}
|
||||
|
||||
public function livestats()
|
||||
{
|
||||
$status = "inactive";
|
||||
|
||||
$response = parent::execute($this->url("metrics"), $this->getAttrs());
|
||||
$body = $response->getBody();
|
||||
|
||||
$lines = explode("\n", $body);
|
||||
|
||||
$data = [
|
||||
"up" => 0,
|
||||
"down" => 0,
|
||||
"pending" => 0,
|
||||
"maintenance" => 0,
|
||||
"unknown" => 0,
|
||||
];
|
||||
|
||||
foreach ($lines as $line) {
|
||||
if (strlen($line) === 0 || strpos($line, '#') === 0) {
|
||||
// If the line is empty or is a comment we can skip it
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strpos($line, 'monitor_status') !== 0) {
|
||||
// If the line is a metric but not a monitor we can ignore it
|
||||
continue;
|
||||
}
|
||||
|
||||
// We only really care about the state, which is the integer at the end
|
||||
// of the line.
|
||||
//
|
||||
// This can be 0 (Down), 1 (Up), 2 (Pending), 3 (Maintenance)
|
||||
//
|
||||
// We only care about the down or up but let's translate all of them.
|
||||
$state = intval(substr($line, strrpos($line, ' ')));
|
||||
|
||||
$data[$this->mapping[$state] ?? 'unknown']++;
|
||||
}
|
||||
|
||||
if ($data["down"] > 0) {
|
||||
$status = "active";
|
||||
}
|
||||
|
||||
return parent::getLiveStats($status, $data);
|
||||
}
|
||||
|
||||
public function url($endpoint)
|
||||
{
|
||||
$api_url = parent::normaliseurl($this->config->url) .
|
||||
$endpoint;
|
||||
|
||||
return $api_url;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"appid": "366c6646eedab83cc4b349f198424d2291cbfa76",
|
||||
"name": "Uptime Kuma",
|
||||
"website": "https://uptime.kuma.pet",
|
||||
"license": "MIT License",
|
||||
"description": "It is a self-hosted monitoring tool like \"Uptime Robot\".",
|
||||
"enhanced": true,
|
||||
"tile_background": "dark",
|
||||
"icon": "uptimekuma.svg"
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<h2>{{ __('app.apps.config') }} ({{ __('app.optional') }}) @include('items.enable')</h2>
|
||||
<div class="items">
|
||||
<input type="hidden" data-config="dataonly" class="config-item" name="config[dataonly]" value="1" />
|
||||
<div class="input">
|
||||
<label>{{ strtoupper(__('app.url')) }}</label>
|
||||
{!! Form::text('config[override_url]', isset($item) ? $item->getconfig()->override_url : null, ['placeholder' => __('app.apps.override'), 'id' => 'override_url', 'class' => 'form-control']) !!}
|
||||
</div>
|
||||
<div class="input">
|
||||
<label>{{ __('app.apps.apikey') }}</label>
|
||||
{!! Form::text('config[apikey]', isset($item) ? ($item->getconfig()->apikey ?? null) : null, ['placeholder' => __('app.apps.apikey'), 'data-config' => 'apikey', 'class' => 'form-control config-item']) !!}
|
||||
</div>
|
||||
<div class="input">
|
||||
<label>Skip TLS verification</label>
|
||||
<div class="toggleinput" style="margin-top: 26px; padding-left: 15px;">
|
||||
{!! Form::hidden('config[ignore_tls]', 0, ['class' => 'config-item', 'data-config' => 'ignore_tls']) !!}
|
||||
<label class="switch">
|
||||
<?php
|
||||
$checked = false;
|
||||
if (isset($item) && !empty($item) && isset($item->getconfig()->ignore_tls)) {
|
||||
$checked = $item->getconfig()->ignore_tls;
|
||||
}
|
||||
$set_checked = $checked ? ' checked="checked"' : '';
|
||||
?>
|
||||
<input type="checkbox" class="config-item" data-config="ignore_tls" name="config[ignore_tls]" value="1" <?php echo $set_checked; ?> />
|
||||
<span class="slider round"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input">
|
||||
<button style="margin-top: 32px;" class="btn test" id="test_config">Test</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,10 @@
|
||||
<ul class="livestats">
|
||||
<li>
|
||||
<span class="title">Up</span>
|
||||
<strong>{!! $up ?? 0 !!}</strong>
|
||||
</li>
|
||||
<li>
|
||||
<span class="title">Down</span>
|
||||
<strong>{!! $down ?? 0 !!}</strong>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace App\SupportedApps\Vaultwarden;
|
||||
|
||||
class Vaultwarden extends \App\SupportedApps
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"appid": "ddf4f264320af1347ef54d424c60fae3b4fcc448",
|
||||
"name": "Vaultwarden",
|
||||
"website": "https://github.com/dani-garcia/vaultwarden",
|
||||
"license": "GNU Affero General Public License v3.0",
|
||||
"description": "Alternative implementation of the Bitwarden server API written in Rust and compatible with upstream Bitwarden clients*, perfect for self-hosted deployment where running the official resource-heavy service might not be ideal.",
|
||||
"enhanced": false,
|
||||
"tile_background": "light",
|
||||
"icon": "vaultwarden.png"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace App\SupportedApps\WireGuard;
|
||||
|
||||
class WireGuard extends \App\SupportedApps
|
||||
{
|
||||
}
|
||||
10
stacks/dashboard/config/www/SupportedApps/WireGuard/app.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"appid": "afef2217e82ee20638490bb102605f6e09789093",
|
||||
"name": "WireGuard",
|
||||
"website": "https://www.wireguard.com",
|
||||
"license": "CNRI Python Open Source GPL Compatible License Agreement",
|
||||
"description": "WireGuard® is an extremely simple yet fast and modern VPN that utilizes state-of-the-art cryptography. It aims to be faster, simpler, leaner, and more useful than IPsec, while avoiding the massive headache. It intends to be considerably more performant than OpenVPN. WireGuard is designed as a general purpose VPN for running on embedded interfaces and super computers alike, fit for many different circumstances. Initially released for the Linux kernel, it is now cross-platform (Windows, macOS, BSD, iOS, Android) and widely deployable. It is currently under heavy development, but already it might be regarded as the most secure, easiest to use, and simplest VPN solution in the industry.",
|
||||
"enhanced": false,
|
||||
"tile_background": "dark",
|
||||
"icon": "wireguard.png"
|
||||
}
|
||||
10
stacks/dashboard/config/www/SupportedApps/ownCloud/app.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"appid": "668b5fcda851fe516fef14e82973beffe32f385a",
|
||||
"name": "ownCloud",
|
||||
"website": "https://owncloud.org",
|
||||
"license": "GNU Affero General Public License v3.0 or later",
|
||||
"description": "ownCloud is a free and open source file hosting service. It also supports extensions for online document editing, calendar and contact synchronization. It's a safe home for all your data.",
|
||||
"enhanced": false,
|
||||
"tile_background": "dark",
|
||||
"icon": "owncloud.png"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace App\SupportedApps\ownCloud;
|
||||
|
||||
class ownCloud extends \App\SupportedApps // phpcs:ignore
|
||||
{
|
||||
}
|
||||
BIN
stacks/dashboard/config/www/app (1).sqlite
Normal file
BIN
stacks/dashboard/config/www/app copy.sqlite
Normal file
BIN
stacks/dashboard/config/www/app-pre.sqlite
Normal file
BIN
stacks/dashboard/config/www/app.sqlite
Normal file
14
stacks/dashboard/config/www/icons/bookstack.svg
Normal file
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 230.397 218.62">
|
||||
<g fill="#fff" fill-rule="evenodd" stroke="#0288d1" stroke-linejoin="round" stroke-width="6">
|
||||
<g stroke-linecap="round">
|
||||
<path d="m98.52 180.166 128.88-74.409-92.058-53.15-128.88 74.409z"></path>
|
||||
<path d="M6.46 127.016v21.26l92.058 53.15 128.88-74.409v-21.26"></path>
|
||||
<path d="m98.52 215.596-92.058-53.15s-7.5-16.918 0-28.346l92.058 53.15 128.88-74.409v28.346L98.52 215.596"></path>
|
||||
<path d="m98.52 130.556 128.88-74.41L135.34 3 6.46 77.406z"></path>
|
||||
<path d="M98.52 130.556 227.4 56.147v28.346L98.52 158.902l-92.058-53.15s-6.071-17.632 0-28.346z"></path>
|
||||
<path d="m98.52 187.256-92.058-53.15s-7.5-16.918 0-28.346l92.058 53.15L227.4 84.501v28.346L98.52 187.256"></path>
|
||||
</g>
|
||||
<path d="m156.82 15.402-55.234 31.89 21.48 1.772 3.069 12.402 55.235-31.89z"></path>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 933 B |
10
stacks/dashboard/config/www/icons/dockge.svg
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640">
|
||||
<g transform="translate(320 325.566) scale(.9545)">
|
||||
<linearGradient id="a" x1="259.78" x2="463.85" y1="261.15" y2="456.49" gradientTransform="translate(-236.647 -213.944)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0%" style="stop-color:#74c2ff;stop-opacity:1"></stop>
|
||||
<stop offset="100%" style="stop-color:#86e6a9;stop-opacity:1"></stop>
|
||||
</linearGradient>
|
||||
<path stroke-linecap="round" d="M131.867-139.049c27.143 27.84 38.257 39.595 71.251 87.328 32.995 47.734 61.323 135.705-15.778 195.772-9.613 7.489-20.602 14.76-32.68 21.607-84.805 48.066-223.333 75.128-316.453 8.625-106.383-75.974-98.31-242.949 17.442-344.789 115.752-101.84 249.074 3.618 276.217 31.457z" style="stroke:#f2f2f2;stroke-opacity:.51;stroke-width:190;stroke-dasharray:none;stroke-linecap:butt;stroke-dashoffset:0;stroke-linejoin:miter;stroke-miterlimit:4;fill:url(#a);fill-rule:nonzero;opacity:1"></path>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1019 B |
142
stacks/dashboard/config/www/icons/dozzle.svg
Normal file
@@ -0,0 +1,142 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.2" viewBox="0 0 1024 1024">
|
||||
<defs>
|
||||
<clipPath id="cp1">
|
||||
<path d="M1115.21-134.62v1241.33H-126.37V-134.62z"></path>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<style>.d{fill:#eb8b00}.h{fill:#f79900}.m{fill:#fea200}.r{fill:#ea8c00}.s{fill:#f59b00}.t{fill:#fea500}.Y{fill:#ffbb14}.Z{fill:#ffa901}.a4{fill:#ffbd11}.a6{fill:#ffce2c}.at{fill:#ffaa03}.aD{fill:#ffc620}.aI{fill:#ffde3f}.aJ{fill:#ffd935}.aK{fill:#ffbc11}.aO{fill:#ffb811}.aP{fill:#ffb208}</style>
|
||||
<g clip-path="url(#cp1)">
|
||||
<path d="m808 677.3 94.5 55.9-143.6 56-51.7-3z" style="fill:#b60"></path>
|
||||
<path d="M956.9 570.9 899 736.6l117-145.7z" style="fill:#b25b00"></path>
|
||||
<path d="m806.5 683.2 14.7-131.9 140.3 20.9z" style="fill:#e08000"></path>
|
||||
<path d="m753.4 572 69.8-19.8-13 127.9z" class="d"></path>
|
||||
<path d="m666.8 618.2 89.2-46 56.8 111.2z" style="fill:#ef9100"></path>
|
||||
<path d="m960 572.2-58.9 161-91.6-53.1z" style="fill:#c76e00"></path>
|
||||
<path d="m616 711.5 92.4 74.4 102.4-107.4z" style="fill:#ce6e00"></path>
|
||||
<path d="m616 714.2 50.6-104.5L812 680.1z" class="d"></path>
|
||||
<path d="m507.8 653.3 109.8 61.5 49.2-99.4z" class="h"></path>
|
||||
<path d="M511.6 489v166.6l155.2-38.8z" style="fill:#ffa902"></path>
|
||||
<path d="m663 621.8 35.1-65.4 61.6 15.7z" style="fill:#f59900"></path>
|
||||
<path d="m652 526 13.3 95.7 36.1-63.8z" style="fill:#fea400"></path>
|
||||
<path d="m505.1 485 161.2 133.7-.7-11.9-11.5-79.9z" style="fill:#ffaf06"></path>
|
||||
<path d="m655.7 486-7.3 40 50.1 31.9z" class="h"></path>
|
||||
<path d="m668.3 420-17.1 107.4-139.6-39.9z" class="m"></path>
|
||||
<path d="m1012.9 432.1-54.1 141.2 55.8 17.6z" style="fill:#be6800"></path>
|
||||
<path d="m960.3 573.6 54.2-141.5-87.8 52.2z" style="fill:#dd7c00"></path>
|
||||
<path d="m928.4 483.1 33.1 90.6-141.2-19.4z" style="fill:#c96b00"></path>
|
||||
<path d="m894.3 438-73.1 118.5 108.4-72.8z" style="fill:#dd8200"></path>
|
||||
<path d="m891.3 436.2 36.9 48.4 86.3-50.8-113.3-14.2z" class="r"></path>
|
||||
<path d="m895.4 437.2 27-37.2 91.4 34.4z" class="r"></path>
|
||||
<path d="m835 415.6 17.1 95.9 42.7-72.5z" class="s"></path>
|
||||
<path d="m816.3 394 59.8 68.5 19.3-23.9z" class="s"></path>
|
||||
<path d="m762.4 365.4 161.7 34.5-30 39.8z" class="t"></path>
|
||||
<path d="M921.2 260.4v140.8l92.2 33.9z" style="fill:#ca7000"></path>
|
||||
<path d="m845.1 313.7 77.3 87.5-1.2-142.2z" style="fill:#e28100"></path>
|
||||
<path d="m761.3 366.5 86-54.5 76.7 89.7z" style="fill:#f49900"></path>
|
||||
<path d="m627.8 340.3 136.8 27.4 85.1-55z" style="fill:#ffb10b"></path>
|
||||
<path d="m631.6 340.7 36.2 78.7 36.4-32.5 62.2-20.6z" style="fill:#ffbb13"></path>
|
||||
<path d="m632.6 340.6 36.4 80-157.6 70.3 1.2-8.1z" style="fill:#ffa905"></path>
|
||||
<path d="m778.1 135.7 68.4 178 74.7-53.3z" style="fill:#faa100"></path>
|
||||
<path d="M511.4 269.3v221.6l122.5-150z" style="fill:#ffb812"></path>
|
||||
<path d="m511.6 270.5 153.8-77.6-33 148z" style="fill:#ffcb24"></path>
|
||||
<path d="m663 190.3-32.1 150.6 218.4-27.2z" style="fill:#ffc31c"></path>
|
||||
<path d="m665.4 192.9 114-57.2L848 315.1z" style="fill:#ffb10a"></path>
|
||||
<path d="M510.3 44.4 664 195.8l117.8-58.9z" style="fill:#ffc119"></path>
|
||||
<path d="m511.6 783.4 200.1 2.5-93.7-74.3z" style="fill:#bf6700"></path>
|
||||
<path d="m511.5 784.1.1-128.8 107.1 57.4z" style="fill:#e68d00"></path>
|
||||
<path d="m511.8 45.2-.4 226.6 154-77.4z" style="fill:#ffd027"></path>
|
||||
<path d="m791.8 880.1 79.1-11-113.5-37.4z" style="fill:#cd7500"></path>
|
||||
<path d="m789.1 878.6 13.7 59.7 67.5-69.8z" style="fill:#c06900"></path>
|
||||
<path d="m669.9 976.8 121.9-99.2 11.6 60z" style="fill:#d47b00"></path>
|
||||
<path d="m595.1 897.7 97.7 63.9 100.5-84z" style="fill:#eb8e00"></path>
|
||||
<path d="m599.7 898.1 157.7-67.2 37.2 47.9z" style="fill:#c66d00"></path>
|
||||
<path d="m598.9 898.7 69.1-71.8 89 4.8-140.7 61.5z" style="fill:#bd6200"></path>
|
||||
<path d="m511.5 825 87.2 76.1 74.1-74.4z" style="fill:#cf7100"></path>
|
||||
<path d="M506.5 1015.9 677 975.2l18.1-16.5-177.8 48.4z" style="fill:#d57500"></path>
|
||||
<path d="m512 1016.2 87.3-119.3 93.8 63.6-177.3 55.4z" style="fill:#e08400"></path>
|
||||
<path d="m441.2 879.5 158.1 21.1-87.3-76z" style="fill:#d87a00"></path>
|
||||
<path d="m442.6 878.9 67.5 137 3.6-.2 85.6-116.9z" style="fill:#f49f00"></path>
|
||||
<path d="m512 1016.2-68.4-138.1-84.3 87.5 145.8 49.8z" style="fill:#ffb308"></path>
|
||||
<path d="m353.2 973 7.1-9.8 147.1 53.1z" style="fill:#ffa600"></path>
|
||||
<path d="m274 829.2 17.1 76.8 153.5-25.9-9.6-4.9z" style="fill:#ffc61d"></path>
|
||||
<path d="m274.7 829.8 169.9 50.7 13.4-12 54-43.6z" style="fill:#ec9300"></path>
|
||||
<path d="m290.1 903.7 63.7 69.4 90.9-94.5z" class="Y"></path>
|
||||
<path d="m229.7 938 62.1-33.7 67.2 70.4z" class="Z"></path>
|
||||
<path d="m222.8 884.3 8.5 53.9 64.6-34.2z" style="fill:#ffc319"></path>
|
||||
<path d="m156.1 869.6 77.3 69.3L224 882z" class="Z"></path>
|
||||
<path d="m273.5 830 5.1 3.6 13.2 70.7-71.9-20z" style="fill:#ffd832"></path>
|
||||
<path d="m155.3 869.6 119.3-40-6.9 10.8-45.2 45z" style="fill:#ffc721"></path>
|
||||
<path d="m396.6 444.5 116 46.1V266z" style="fill:#ffc823"></path>
|
||||
<path d="m332.1 395.5 30.2 47.4h38.8z" class="a4"></path>
|
||||
<path d="m360.6 514.2 1.7-72.6 40.8-.3z" style="fill:#ffc524"></path>
|
||||
<path d="m355.3 518.2-5.2 60 52.2-137z" class="a6"></path>
|
||||
<path d="m348.9 577 162.7-89-112-45.1z" style="fill:#ffc016"></path>
|
||||
<path d="m436.2 617 76.4 41.7V484.1z" style="fill:#ffb708"></path>
|
||||
<path d="m346.6 576.8 91.8 41.4 74.2-132z" style="fill:#ffc011"></path>
|
||||
<path d="m512.6 653.9.3 129.1-3.7-.5-122.3-83.7c-1.2 0 125.7-44.9 125.7-44.9" style="fill:#f59f00"></path>
|
||||
<path d="m389.2 702.2 49.3-88.1 73.5 40.4-.4 2.5z" style="fill:#ffb609"></path>
|
||||
<path d="m390.3 707.8-42.5-131.2 92.9 38.1z" style="fill:#ffc01a"></path>
|
||||
<path d="M266.8 788.5 377.9 705l15.2-4.5 119.5 82.8z" style="fill:#d57900"></path>
|
||||
<path d="m260.4 730.9 9 57.2 123.7-90.4z" style="fill:#e08500"></path>
|
||||
<path d="m289.8 623.9 103.3 77.2-4.9 1.9-128.6 28.8z" style="fill:#f89f00"></path>
|
||||
<path d="m350.7 576.2 42.4 126-104.6-76.6z" style="fill:#ffba0c"></path>
|
||||
<path d="m301.8 571.3 50.8 6.9 7.4-64z" class="a6"></path>
|
||||
<path d="m289.5 626.7 65.4-49.6-51.6-8.5z" style="fill:#ffc41f"></path>
|
||||
<path d="m8.7 589.4 113.5 143.8 24.5-33.1L17.3 592.8z" style="fill:#da7f00"></path>
|
||||
<path d="m143.8 700.1 127.9 89.1-150.8-56z" style="fill:#d07700"></path>
|
||||
<path d="M142.8 700.5v2.8l127.3 85.1-8.5-58.1z" style="fill:#f09600"></path>
|
||||
<path d="m292.9 624.1-31.3 108L144 701.8l144.3-77.6z" style="fill:#ffae05"></path>
|
||||
<path d="m209.4 560-67.7 143.9 150.1-78.5z" style="fill:#ffbe1a"></path>
|
||||
<path d="m207.1 558.8 83.6 67.9 14.8-59.2z" style="fill:#ffcd29"></path>
|
||||
<path d="m83.4 543.5 128.3 14.8-66.5 143.3z" style="fill:#fb9c00"></path>
|
||||
<path d="m84.7 544 63.2 161.6L7.4 588.8z" style="fill:#e38500"></path>
|
||||
<path d="m169.6 489 41.5 72-131.4-16.2z" style="fill:#ffae07"></path>
|
||||
<path d="M10.8 432.1 8 589.8l81.4-45.6z" class="m"></path>
|
||||
<path d="m129.5 414.5-43.2 129-76.1-110.8z" style="fill:#ffad02"></path>
|
||||
<path d="m127.5 416.5 42.1 75.2-86.3 53.4z" class="t"></path>
|
||||
<path d="m126.2 416.5 59 8.7-15.7 68.1z" style="fill:#ffaf0a"></path>
|
||||
<path d="m126.3 416.8 98.9-32.6-41.2 41.5-56.7-7.2z" class="at"></path>
|
||||
<path d="M367.8 187.7 512.4 44.3l.4 225.4-4.8.3z" style="fill:#ffda35"></path>
|
||||
<path d="m329 349.3 36.2-165.7 146.4 86.9z" style="fill:#ffcd23"></path>
|
||||
<path d="m276.2 330.3 55.1 19.5L368.4 185z" style="fill:#ffce28"></path>
|
||||
<path d="m327.8 347.2 184.8-78.6-114.5 176.6z" style="fill:#ffd834"></path>
|
||||
<path d="m327.7 344.1 3.5 52.6 65.5 44.9z" style="fill:#ffc21b"></path>
|
||||
<path d="m329.2 346.6 3.7 50.5-64.4-28.8z" class="Y"></path>
|
||||
<path d="m275 328.5-3.3 41.2 60.4-21.6z" style="fill:#ffae08"></path>
|
||||
<path d="m151.8 303.1 216.6-117.2 1.1 1.7-93.4 144.7z" style="fill:#ffd331"></path>
|
||||
<path d="m153.8 302.1 123.8 28.5-151.8 88.8 1.1-10.3z" style="fill:#ffc722"></path>
|
||||
<path d="m155.9 297.8-29.3 119.3L9.5 433.8z" style="fill:#ffb806"></path>
|
||||
<path d="m10.2 435.7 91.9-172.3 53.2 37.3z" class="aD"></path>
|
||||
<path d="m243.8 136.4 4.8.6-93.8 165.8-53.2-38.5z" style="fill:#ffce26"></path>
|
||||
<path d="M512 45.2v5.1L369.4 187.2l-123.5-50.3z" style="fill:#ffe350"></path>
|
||||
<path d="m247.8 136.4 122.8 49.9-219.3 118.4z" style="fill:#ffd839"></path>
|
||||
<path d="m276.9 328.8-3.8 40.9-146.3 48.1z" style="fill:#ffb40f"></path>
|
||||
<path d="m149.8 68.4 52.9 34.1L218 82.4z" class="aD"></path>
|
||||
<path d="m216.8 53.3.9 29.8-69.6-13.7z" class="a6"></path>
|
||||
<path d="m209.6 31.6 7.5 23.4-68.2 14.9z" class="aI"></path>
|
||||
<path d="m150.9 70.4 31.9-62.2 28.3 25.6z" class="aJ"></path>
|
||||
<path d="M151.6 70.4 137 7.2l46.9 1.2z" class="aJ"></path>
|
||||
<path d="M153.1 69.5 137.8 6.8l-34 39z" class="aK"></path>
|
||||
<path d="m156.3 70-52.7-25.7-.7 28.9z" style="fill:#ffc420"></path>
|
||||
<path d="m156.7 67.7-47.4 26.1-7.2-21.5z" style="fill:#ffb910"></path>
|
||||
<path d="m152.7 68.3-5.8 54.6-38.3-29.6z" style="fill:#ffad09"></path>
|
||||
<path d="m178.3 121.2-26.5-53-5.5 54.7z" class="aO"></path>
|
||||
<path d="m203.4 101.8-53-34.6 25.1 55.2z" class="aP"></path>
|
||||
<path d="m200.4 177 1.8-75.2 43.4 35.5z" class="aP"></path>
|
||||
<path d="M203.2 180 177 120.9l26.4-19.6z" class="a4"></path>
|
||||
<path d="m877.8 68.7-55.9 35.1L808 83.1z" class="aD"></path>
|
||||
<path d="m807.2 55.7.3 29.5 69-15z" class="a6"></path>
|
||||
<path d="M813.3 33.9 807 58.1l68.7 13.1z" class="aI"></path>
|
||||
<path d="M873.7 71.8 841.8 9.6l-28 25.6z" class="aJ"></path>
|
||||
<path d="M872.7 73.5 889 8.2l-48.9 1.6z" class="aJ"></path>
|
||||
<path d="m869.9 74.2 16.6-67 35.9 39.5z" class="aK"></path>
|
||||
<path d="m871.7 71.2 49.9-25.4.2 29.4z" class="at"></path>
|
||||
<path d="m869.9 70 45.4 25.2 7.2-21.4z" style="fill:#fca400"></path>
|
||||
<path d="m871.9 69.8 5.8 54.5 38.7-31z" style="fill:#fb9e00"></path>
|
||||
<path d="m846.3 122.5 26.9-52.9 5.1 54.7z" class="aO"></path>
|
||||
<path d="m820.6 103 54.9-34.1-27.8 53.6z" class="aP"></path>
|
||||
<path d="m775.7 135.7 75.2-13.3-30.3 52.1z" style="fill:#e88e00"></path>
|
||||
<path d="m773 138 52.8-36.6 27.8 21.9z" style="fill:#fca500"></path>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 10 KiB |
25
stacks/dashboard/config/www/icons/filebrowser.svg
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" id="prefix__svg44" fill-rule="evenodd" clip-rule="evenodd" image-rendering="optimizeQuality" shape-rendering="geometricPrecision" text-rendering="geometricPrecision" version="1.1" viewBox="0 0 560 560">
|
||||
<defs id="prefix__defs4">
|
||||
<style id="style2" type="text/css">.prefix__fil1{fill:#fefefe}.prefix__fil6{fill:#006498}.prefix__fil5{fill:#bdeaff}</style>
|
||||
</defs>
|
||||
<g id="prefix__g85" transform="translate(-70 -70)">
|
||||
<path id="prefix__path9" fill="#fefefe" d="M350 71c154 0 279 125 279 279S504 629 350 629 71 504 71 350 196 71 350 71z" class="prefix__fil1"></path>
|
||||
<path id="prefix__path11" fill="#332c2b" fill-opacity=".149" d="m475 236 118 151c3 116-149 252-292 198l-76-99 114-156s138-95 136-94z"></path>
|
||||
<path id="prefix__path13" fill="#2bbcff" d="M231 211h208l38 24v246c0 5-3 8-8 8H231c-5 0-8-3-8-8V219c0-5 3-8 8-8z"></path>
|
||||
<path id="prefix__path15" fill="#53c6fc" d="M231 211h208l38 24v2l-37-23H231c-4 0-7 3-7 7v263c-1-1-1-2-1-3V219c0-5 3-8 8-8z"></path>
|
||||
<path id="prefix__polygon17" fill="#bdeaff" d="M305 212h113v98H305z" class="prefix__fil5"></path>
|
||||
<path id="prefix__path19" fill="#bdeaff" d="M255 363h189c3 0 5 2 5 4v116H250V367c0-2 2-4 5-4z" class="prefix__fil5"></path>
|
||||
<path id="prefix__polygon21" fill="#006498" d="M250 470h199v13H250z" class="prefix__fil6"></path>
|
||||
<path id="prefix__path23" fill="#006498" d="M380 226h10c3 0 6 2 6 5v40c0 3-3 6-6 6h-10c-3 0-6-3-6-6v-40c0-3 3-5 6-5z" class="prefix__fil6"></path>
|
||||
<path id="prefix__path25" fill="#fefefe" d="M254 226c10 0 17 7 17 17 0 9-7 16-17 16-9 0-17-7-17-16 0-10 8-17 17-17z" class="prefix__fil1"></path>
|
||||
<path id="prefix__path27" fill="#006498" d="M267 448h165c2 0 3 1 3 3 0 1-1 3-3 3H267c-2 0-3-2-3-3 0-2 1-3 3-3z" class="prefix__fil6"></path>
|
||||
<path id="prefix__path29" fill="#006498" d="M267 415h165c2 0 3 1 3 3 0 1-1 2-3 2H267c-2 0-3-1-3-2 0-2 1-3 3-3z" class="prefix__fil6"></path>
|
||||
<path id="prefix__path31" fill="#006498" d="M267 381h165c2 0 3 2 3 3 0 2-1 3-3 3H267c-2 0-3-1-3-3 0-1 1-3 3-3z" class="prefix__fil6"></path>
|
||||
<path id="prefix__path33" fill="#fefefe" d="M236 472c3 0 5 2 5 5 0 2-2 4-5 4s-5-2-5-4c0-3 2-5 5-5z" class="prefix__fil1"></path>
|
||||
<path id="prefix__path35" fill="#fefefe" d="M463 472c3 0 5 2 5 5 0 2-2 4-5 4s-5-2-5-4c0-3 2-5 5-5z" class="prefix__fil1"></path>
|
||||
<path id="prefix__polygon37" fill="#006498" d="M305 212h-21v98h21z" class="prefix__fil6"></path>
|
||||
<path id="prefix__path39" fill="#0ea5eb" d="M477 479v2c0 5-3 8-8 8H231c-5 0-8-3-8-8v-2c0 4 3 8 8 8h238c5 0 8-4 8-8z"></path>
|
||||
<path id="prefix__path41" fill="#2979ff" d="M350 70c155 0 280 125 280 280S505 630 350 630 70 505 70 350 195 70 350 70zm0 46c129 0 234 105 234 234S479 584 350 584 116 479 116 350s105-234 234-234z"></path>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.8 KiB |
BIN
stacks/dashboard/config/www/icons/ittools.png
Normal file
|
After Width: | Height: | Size: 6.7 KiB |
15
stacks/dashboard/config/www/icons/jellyfin.svg
Normal file
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 465.365 465.363">
|
||||
<defs>
|
||||
<linearGradient id="a" x1="110.25" x2="496.14" y1="213.3" y2="436.09" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" style="stop-color:#aa5cc3"></stop>
|
||||
<stop offset="1" style="stop-color:#00a4dc"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient xlink:href="#a" id="b" x1="110.25" x2="496.14" y1="213.3" y2="436.09" gradientUnits="userSpaceOnUse"></linearGradient>
|
||||
<linearGradient xlink:href="#a" id="c" x1="110.25" x2="496.14" y1="213.3" y2="436.09" gradientUnits="userSpaceOnUse"></linearGradient>
|
||||
</defs>
|
||||
<g fill="url(#a)" transform="translate(-23.29 -23.3)">
|
||||
<path d="M256 201.6c-20.4 0-86.2 119.3-76.2 139.4 10 20.1 142.5 19.9 152.4 0 9.9-19.9-55.7-139.4-76.2-139.4z" style="fill:url(#b)"></path>
|
||||
<path d="M256 23.3c-61.6 0-259.8 359.4-229.6 420.1 30.2 60.7 429.3 60 459.2 0 29.9-60-168-420.1-229.6-420.1Zm150.5 367.5c-19.6 39.3-281.1 39.8-300.9 0C85.8 351 215.7 115.5 256 115.5c40.3 0 170.1 235.9 150.5 275.3z" style="fill:url(#c)"></path>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
BIN
stacks/dashboard/config/www/icons/nginxproxymanager.png
Normal file
|
After Width: | Height: | Size: 8.9 KiB |
BIN
stacks/dashboard/config/www/icons/onlyoffice.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
stacks/dashboard/config/www/icons/owncloud.png
Normal file
|
After Width: | Height: | Size: 8.8 KiB |
14
stacks/dashboard/config/www/icons/pihole.svg
Normal file
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 258.305 380">
|
||||
<linearGradient id="a" x1="7.926" x2="204.053" y1="58.61" y2="58.61" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#12b212"></stop>
|
||||
<stop offset="1" stop-color="#0f0"></stop>
|
||||
</linearGradient>
|
||||
<g stroke-width="2.925">
|
||||
<path fill="url(#a)" d="M106.925 116.781C59.488 111.721 11.7 75.865 7.926 0c73.613 0 112.98 43.577 116.781 112.628 13.922-82.826 79.17-73.116 79.17-73.116 3.1 46.94-35.446 75.398-79.17 77.767C112.424 91.395 38.84 27.9 38.84 27.9a.205.205 0 0 0-.322.234s71.01 61.857 68.407 88.646"></path>
|
||||
<path fill="#980200" d="M129.153 380c-4.592-.263-47.438-1.901-50.041-50.04-2.106-29.247 20.999-50.802 20.999-79.2-5.235-70.806-100.11-62.032-100.11 0a58.318 58.318 0 0 0 17.05 41.354l70.689 70.718a58.318 58.318 0 0 0 41.354 17.051"></path>
|
||||
<path fill="red" d="M258.305 250.789c-.263 4.592-1.9 47.438-50.04 50.04-29.247 2.106-50.83-20.998-79.2-20.998-70.806 5.235-62.032 100.081 0 100.081a58.318 58.318 0 0 0 41.355-17.05l70.747-70.69a58.318 58.318 0 0 0 17.05-41.354"></path>
|
||||
<path fill="#980200" d="M129.153 121.636c4.592.263 47.438 1.901 50.04 50.041 2.106 29.247-20.998 50.801-20.998 79.2 5.235 70.805 100.081 62.031 100.081 0a58.318 58.318 0 0 0-17.05-41.355l-70.719-70.747a58.318 58.318 0 0 0-41.354-17.051"></path>
|
||||
<path fill="red" d="M.234 250.789c.263-4.592 1.901-47.438 50.04-50.04 29.247-2.107 50.831 20.998 79.2 20.998 70.806-5.323 62.032-100.081 0-100.081a58.318 58.318 0 0 0-41.354 17.05l-70.747 70.718A58.318 58.318 0 0 0 .322 250.79"></path>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
11
stacks/dashboard/config/www/icons/uptimekuma.svg
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 164.179 151.11">
|
||||
<defs>
|
||||
<linearGradient id="a" x1="259.78" x2="463.85" y1="261.15" y2="456.49" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0%" stop-color="#5cdd8b"></stop>
|
||||
<stop offset="100%" stop-color="#86e6a9"></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<path d="M490.4 235.64c53.69 122.74 53.69 199.7 0 230.86-80.55 46.74-290.44 60.99-350.86-10.86-40.28-47.9-40.28-121.24 0-220 40.96-67.46 99.17-101.19 174.63-101.19 75.47 0 134.21 33.73 176.23 101.19z" style="fill:url(#a)" transform="translate(-2.685 -9.115) scale(.26458)"></path>
|
||||
<path fill="none" d="M490.4 235.64c53.69 122.74 53.69 199.7 0 230.86-80.55 46.74-290.44 60.99-350.86-10.86-40.28-47.9-40.28-121.24 0-220 40.96-67.46 99.17-101.19 174.63-101.19 75.47 0 134.21 33.73 176.23 101.19z" style="fill-opacity:0;stroke:#f2f2f2;stroke-width:200;stroke-opacity:.51" transform="translate(-2.685 -9.115) scale(.26458)"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1003 B |
BIN
stacks/dashboard/config/www/icons/vaultwarden.png
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
stacks/dashboard/config/www/icons/wireguard.png
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
34
stacks/dashboard/config/www/index.html
Normal file
@@ -0,0 +1,34 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Welcome to our server</title>
|
||||
<style>
|
||||
body{
|
||||
font-family: Helvetica, Arial, sans-serif;
|
||||
}
|
||||
.message{
|
||||
width:330px;
|
||||
padding:20px 40px;
|
||||
margin:0 auto;
|
||||
background-color:#f9f9f9;
|
||||
border:1px solid #ddd;
|
||||
}
|
||||
center{
|
||||
margin:40px 0;
|
||||
}
|
||||
h1{
|
||||
font-size: 18px;
|
||||
line-height: 26px;
|
||||
}
|
||||
p{
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="message">
|
||||
<h1>Welcome to our server</h1>
|
||||
<p>The website is currently being setup under this address.</p>
|
||||
<p>For help and support, please contact: <a href="me@example.com">me@example.com</a></p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
44
stacks/dashboard/config/www/searchproviders.yaml
Normal file
@@ -0,0 +1,44 @@
|
||||
tiles:
|
||||
id: tiles
|
||||
name: Tiles
|
||||
target: _blank
|
||||
|
||||
baidu:
|
||||
id: baidu
|
||||
url: https://www.baidu.com/s
|
||||
name: Baidu
|
||||
method: get
|
||||
target: _blank
|
||||
query: wd
|
||||
|
||||
bing:
|
||||
id: bing
|
||||
url: https://www.bing.com/search
|
||||
name: Bing
|
||||
method: get
|
||||
target: _blank
|
||||
query: q
|
||||
|
||||
ddg:
|
||||
id: ddg
|
||||
url: https://duckduckgo.com/
|
||||
name: DuckDuckGo
|
||||
method: get
|
||||
target: _blank
|
||||
query: q
|
||||
|
||||
google:
|
||||
id: google
|
||||
url: https://www.google.com/search
|
||||
name: Google
|
||||
method: get
|
||||
target: _blank
|
||||
query: q
|
||||
|
||||
startpage:
|
||||
id: startpage
|
||||
url: https://www.startpage.com/do/dsearch
|
||||
name: Startpage
|
||||
method: get
|
||||
target: _blank
|
||||
query: query
|
||||
@@ -0,0 +1,11 @@
|
||||
services:
|
||||
dozzle:
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
networks:
|
||||
- dockge_default
|
||||
image: amir20/dozzle:latest
|
||||
restart: always
|
||||
networks:
|
||||
dockge_default:
|
||||
external: true
|
||||
@@ -0,0 +1,10 @@
|
||||
services:
|
||||
it-tools:
|
||||
container_name: it-tools
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- dockge_default
|
||||
image: corentinth/it-tools:latest
|
||||
networks:
|
||||
dockge_default:
|
||||
external: true
|
||||
@@ -0,0 +1,19 @@
|
||||
services:
|
||||
jellyfin:
|
||||
image: jellyfin/jellyfin
|
||||
container_name: jellyfin
|
||||
user: root
|
||||
networks:
|
||||
- dockge_default
|
||||
volumes:
|
||||
- ./config:/config
|
||||
- ./cache:/cache
|
||||
- ./media:/media:ro
|
||||
- ./fonts:/usr/local/share/fonts/custom:ro
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
JELLYFIN_PublishedServerUrl: https://video.?domain?
|
||||
TZ: ?timezone?
|
||||
networks:
|
||||
dockge_default:
|
||||
external: true
|
||||
@@ -0,0 +1,14 @@
|
||||
services:
|
||||
uptime-kuma:
|
||||
image: louislam/uptime-kuma:2
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ./data:/app/data
|
||||
networks:
|
||||
- dockge_default
|
||||
dns:
|
||||
- 1.1.1.1
|
||||
- 8.8.8.8
|
||||
networks:
|
||||
dockge_default:
|
||||
external: true
|
||||
@@ -0,0 +1,29 @@
|
||||
services:
|
||||
app:
|
||||
image: jc21/nginx-proxy-manager:latest
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- dockge_default
|
||||
ports:
|
||||
# These ports are in format <host-port>:<container-port>
|
||||
- 80:80 # Public HTTP Port
|
||||
- 443:443 # Public HTTPS Port
|
||||
- 81:81 # Admin Web Port
|
||||
# Add any other Stream port you want to expose
|
||||
# - '21:21' # FTP
|
||||
|
||||
environment:
|
||||
TZ: ?timezone?
|
||||
# Uncomment this if you want to change the location of
|
||||
# the SQLite DB file within the container
|
||||
# DB_SQLITE_FILE: "/data/database.sqlite"
|
||||
|
||||
# Uncomment this if IPv6 is not enabled on your host
|
||||
# DISABLE_IPV6: 'true'
|
||||
|
||||
volumes:
|
||||
- ./data:/data
|
||||
- ./letsencrypt:/etc/letsencrypt
|
||||
networks:
|
||||
dockge_default:
|
||||
external: true
|
||||
BIN
stacks/npm/data/database-post-placeholder-pre-user.sqlite
Normal file
BIN
stacks/npm/data/database-pre.sqlite
Normal file
BIN
stacks/npm/data/database.sqlite
Normal file
67
stacks/npm/data/nginx/proxy_host/1.conf
Normal file
@@ -0,0 +1,67 @@
|
||||
# ------------------------------------------------------------
|
||||
# docker.sdgserver.online
|
||||
# ------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
map $scheme $hsts_header {
|
||||
https "max-age=63072000; preload";
|
||||
}
|
||||
|
||||
server {
|
||||
set $forward_scheme http;
|
||||
set $server "?localip?";
|
||||
set $port 5001;
|
||||
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
|
||||
|
||||
server_name docker.?domain?;
|
||||
http2 off;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $http_connection;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
|
||||
access_log /data/logs/proxy-host-1_access.log proxy;
|
||||
error_log /data/logs/proxy-host-1_error.log warn;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
location / {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $http_connection;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
|
||||
# Proxy!
|
||||
include conf.d/include/proxy.conf;
|
||||
}
|
||||
|
||||
|
||||
# Custom
|
||||
include /data/nginx/custom/server_proxy[.]conf;
|
||||
}
|
||||
59
stacks/npm/data/nginx/proxy_host/10.conf
Normal file
@@ -0,0 +1,59 @@
|
||||
# ------------------------------------------------------------
|
||||
# proxy.sdgserver.online
|
||||
# ------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
map $scheme $hsts_header {
|
||||
https "max-age=63072000; preload";
|
||||
}
|
||||
|
||||
server {
|
||||
set $forward_scheme http;
|
||||
set $server "?localip?";
|
||||
set $port 81;
|
||||
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
|
||||
|
||||
server_name proxy.?domain?;
|
||||
http2 off;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
access_log /data/logs/proxy-host-10_access.log proxy;
|
||||
error_log /data/logs/proxy-host-10_error.log warn;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
location / {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Proxy!
|
||||
include conf.d/include/proxy.conf;
|
||||
}
|
||||
|
||||
|
||||
# Custom
|
||||
include /data/nginx/custom/server_proxy[.]conf;
|
||||
}
|
||||
67
stacks/npm/data/nginx/proxy_host/11.conf
Normal file
@@ -0,0 +1,67 @@
|
||||
# ------------------------------------------------------------
|
||||
# office.sdgserver.online
|
||||
# ------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
map $scheme $hsts_header {
|
||||
https "max-age=63072000; preload";
|
||||
}
|
||||
|
||||
server {
|
||||
set $forward_scheme http;
|
||||
set $server "documentserver";
|
||||
set $port 80;
|
||||
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
|
||||
|
||||
server_name office.?domain?;
|
||||
http2 off;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $http_connection;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
|
||||
access_log /data/logs/proxy-host-11_access.log proxy;
|
||||
error_log /data/logs/proxy-host-11_error.log warn;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
location / {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $http_connection;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
|
||||
# Proxy!
|
||||
include conf.d/include/proxy.conf;
|
||||
}
|
||||
|
||||
|
||||
# Custom
|
||||
include /data/nginx/custom/server_proxy[.]conf;
|
||||
}
|
||||
67
stacks/npm/data/nginx/proxy_host/12.conf
Normal file
@@ -0,0 +1,67 @@
|
||||
# ------------------------------------------------------------
|
||||
# cloud.sdgserver.online
|
||||
# ------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
map $scheme $hsts_header {
|
||||
https "max-age=63072000; preload";
|
||||
}
|
||||
|
||||
server {
|
||||
set $forward_scheme http;
|
||||
set $server "owncloud_server";
|
||||
set $port 8080;
|
||||
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
|
||||
|
||||
server_name cloud.?domain?;
|
||||
http2 off;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $http_connection;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
|
||||
access_log /data/logs/proxy-host-12_access.log proxy;
|
||||
error_log /data/logs/proxy-host-12_error.log warn;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
location / {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $http_connection;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
|
||||
# Proxy!
|
||||
include conf.d/include/proxy.conf;
|
||||
}
|
||||
|
||||
|
||||
# Custom
|
||||
include /data/nginx/custom/server_proxy[.]conf;
|
||||
}
|
||||
67
stacks/npm/data/nginx/proxy_host/13.conf
Normal file
@@ -0,0 +1,67 @@
|
||||
# ------------------------------------------------------------
|
||||
# www.sdgserver.online
|
||||
# ------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
map $scheme $hsts_header {
|
||||
https "max-age=63072000; preload";
|
||||
}
|
||||
|
||||
server {
|
||||
set $forward_scheme http;
|
||||
set $server "site";
|
||||
set $port 80;
|
||||
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
|
||||
|
||||
server_name www.?domain?;
|
||||
http2 off;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $http_connection;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
|
||||
access_log /data/logs/proxy-host-13_access.log proxy;
|
||||
error_log /data/logs/proxy-host-13_error.log warn;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
location / {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $http_connection;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
|
||||
# Proxy!
|
||||
include conf.d/include/proxy.conf;
|
||||
}
|
||||
|
||||
|
||||
# Custom
|
||||
include /data/nginx/custom/server_proxy[.]conf;
|
||||
}
|
||||
67
stacks/npm/data/nginx/proxy_host/14.conf
Normal file
@@ -0,0 +1,67 @@
|
||||
# ------------------------------------------------------------
|
||||
# vault.sdgserver.online
|
||||
# ------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
map $scheme $hsts_header {
|
||||
https "max-age=63072000; preload";
|
||||
}
|
||||
|
||||
server {
|
||||
set $forward_scheme http;
|
||||
set $server "vaultwarden";
|
||||
set $port 80;
|
||||
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
|
||||
|
||||
server_name vault.?domain?;
|
||||
http2 off;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $http_connection;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
|
||||
access_log /data/logs/proxy-host-14_access.log proxy;
|
||||
error_log /data/logs/proxy-host-14_error.log warn;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
location / {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $http_connection;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
|
||||
# Proxy!
|
||||
include conf.d/include/proxy.conf;
|
||||
}
|
||||
|
||||
|
||||
# Custom
|
||||
include /data/nginx/custom/server_proxy[.]conf;
|
||||
}
|
||||
67
stacks/npm/data/nginx/proxy_host/15.conf
Normal file
@@ -0,0 +1,67 @@
|
||||
# ------------------------------------------------------------
|
||||
# vpn.sdgserver.online
|
||||
# ------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
map $scheme $hsts_header {
|
||||
https "max-age=63072000; preload";
|
||||
}
|
||||
|
||||
server {
|
||||
set $forward_scheme http;
|
||||
set $server "wireguard";
|
||||
set $port 51821;
|
||||
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
|
||||
|
||||
server_name vpn.?domain?;
|
||||
http2 off;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $http_connection;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
|
||||
access_log /data/logs/proxy-host-15_access.log proxy;
|
||||
error_log /data/logs/proxy-host-15_error.log warn;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
location / {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $http_connection;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
|
||||
# Proxy!
|
||||
include conf.d/include/proxy.conf;
|
||||
}
|
||||
|
||||
|
||||
# Custom
|
||||
include /data/nginx/custom/server_proxy[.]conf;
|
||||
}
|
||||
67
stacks/npm/data/nginx/proxy_host/16.conf
Normal file
@@ -0,0 +1,67 @@
|
||||
# ------------------------------------------------------------
|
||||
# mail.sdgserver.online
|
||||
# ------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
map $scheme $hsts_header {
|
||||
https "max-age=63072000; preload";
|
||||
}
|
||||
|
||||
server {
|
||||
set $forward_scheme https;
|
||||
set $server "?localip?";
|
||||
set $port 1443;
|
||||
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
|
||||
|
||||
server_name mail.?domain?;
|
||||
http2 off;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $http_connection;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
|
||||
access_log /data/logs/proxy-host-16_access.log proxy;
|
||||
error_log /data/logs/proxy-host-16_error.log warn;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
location / {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $http_connection;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
|
||||
# Proxy!
|
||||
include conf.d/include/proxy.conf;
|
||||
}
|
||||
|
||||
|
||||
# Custom
|
||||
include /data/nginx/custom/server_proxy[.]conf;
|
||||
}
|
||||
59
stacks/npm/data/nginx/proxy_host/17.conf
Normal file
@@ -0,0 +1,59 @@
|
||||
# ------------------------------------------------------------
|
||||
# dozzle.sdgserver.online
|
||||
# ------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
map $scheme $hsts_header {
|
||||
https "max-age=63072000; preload";
|
||||
}
|
||||
|
||||
server {
|
||||
set $forward_scheme http;
|
||||
set $server "dozzle";
|
||||
set $port 8080;
|
||||
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
|
||||
|
||||
server_name dozzle.?domain?;
|
||||
http2 off;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
access_log /data/logs/proxy-host-17_access.log proxy;
|
||||
error_log /data/logs/proxy-host-17_error.log warn;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
location / {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Proxy!
|
||||
include conf.d/include/proxy.conf;
|
||||
}
|
||||
|
||||
|
||||
# Custom
|
||||
include /data/nginx/custom/server_proxy[.]conf;
|
||||
}
|
||||
59
stacks/npm/data/nginx/proxy_host/18.conf
Normal file
@@ -0,0 +1,59 @@
|
||||
# ------------------------------------------------------------
|
||||
# dns.sdgserver.online
|
||||
# ------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
map $scheme $hsts_header {
|
||||
https "max-age=63072000; preload";
|
||||
}
|
||||
|
||||
server {
|
||||
set $forward_scheme http;
|
||||
set $server "pihole";
|
||||
set $port 80;
|
||||
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
|
||||
|
||||
server_name dns.?domain?;
|
||||
http2 off;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
access_log /data/logs/proxy-host-18_access.log proxy;
|
||||
error_log /data/logs/proxy-host-18_error.log warn;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
location / {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Proxy!
|
||||
include conf.d/include/proxy.conf;
|
||||
}
|
||||
|
||||
|
||||
# Custom
|
||||
include /data/nginx/custom/server_proxy[.]conf;
|
||||
}
|
||||
67
stacks/npm/data/nginx/proxy_host/2.conf
Normal file
@@ -0,0 +1,67 @@
|
||||
# ------------------------------------------------------------
|
||||
# docs.sdgserver.online
|
||||
# ------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
map $scheme $hsts_header {
|
||||
https "max-age=63072000; preload";
|
||||
}
|
||||
|
||||
server {
|
||||
set $forward_scheme http;
|
||||
set $server "bookstack";
|
||||
set $port 80;
|
||||
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
|
||||
|
||||
server_name docs.?domain?;
|
||||
http2 off;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $http_connection;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
|
||||
access_log /data/logs/proxy-host-2_access.log proxy;
|
||||
error_log /data/logs/proxy-host-2_error.log warn;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
location / {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $http_connection;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
|
||||
# Proxy!
|
||||
include conf.d/include/proxy.conf;
|
||||
}
|
||||
|
||||
|
||||
# Custom
|
||||
include /data/nginx/custom/server_proxy[.]conf;
|
||||
}
|
||||
67
stacks/npm/data/nginx/proxy_host/3.conf
Normal file
@@ -0,0 +1,67 @@
|
||||
# ------------------------------------------------------------
|
||||
# browser.sdgserver.online
|
||||
# ------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
map $scheme $hsts_header {
|
||||
https "max-age=63072000; preload";
|
||||
}
|
||||
|
||||
server {
|
||||
set $forward_scheme http;
|
||||
set $server "browser";
|
||||
set $port 80;
|
||||
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
|
||||
|
||||
server_name browser.?domain?;
|
||||
http2 off;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $http_connection;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
|
||||
access_log /data/logs/proxy-host-3_access.log proxy;
|
||||
error_log /data/logs/proxy-host-3_error.log warn;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
location / {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $http_connection;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
|
||||
# Proxy!
|
||||
include conf.d/include/proxy.conf;
|
||||
}
|
||||
|
||||
|
||||
# Custom
|
||||
include /data/nginx/custom/server_proxy[.]conf;
|
||||
}
|
||||
67
stacks/npm/data/nginx/proxy_host/4.conf
Normal file
@@ -0,0 +1,67 @@
|
||||
# ------------------------------------------------------------
|
||||
# convert.sdgserver.online
|
||||
# ------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
map $scheme $hsts_header {
|
||||
https "max-age=63072000; preload";
|
||||
}
|
||||
|
||||
server {
|
||||
set $forward_scheme http;
|
||||
set $server "convertx";
|
||||
set $port 3000;
|
||||
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
|
||||
|
||||
server_name convert.?domain?;
|
||||
http2 off;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $http_connection;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
|
||||
access_log /data/logs/proxy-host-4_access.log proxy;
|
||||
error_log /data/logs/proxy-host-4_error.log warn;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
location / {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $http_connection;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
|
||||
# Proxy!
|
||||
include conf.d/include/proxy.conf;
|
||||
}
|
||||
|
||||
|
||||
# Custom
|
||||
include /data/nginx/custom/server_proxy[.]conf;
|
||||
}
|
||||
67
stacks/npm/data/nginx/proxy_host/5.conf
Normal file
@@ -0,0 +1,67 @@
|
||||
# ------------------------------------------------------------
|
||||
# dash.sdgserver.online
|
||||
# ------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
map $scheme $hsts_header {
|
||||
https "max-age=63072000; preload";
|
||||
}
|
||||
|
||||
server {
|
||||
set $forward_scheme http;
|
||||
set $server "dashboard";
|
||||
set $port 80;
|
||||
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
|
||||
|
||||
server_name dash.?domain?;
|
||||
http2 off;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $http_connection;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
|
||||
access_log /data/logs/proxy-host-5_access.log proxy;
|
||||
error_log /data/logs/proxy-host-5_error.log warn;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
location / {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $http_connection;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
|
||||
# Proxy!
|
||||
include conf.d/include/proxy.conf;
|
||||
}
|
||||
|
||||
|
||||
# Custom
|
||||
include /data/nginx/custom/server_proxy[.]conf;
|
||||
}
|
||||
67
stacks/npm/data/nginx/proxy_host/6.conf
Normal file
@@ -0,0 +1,67 @@
|
||||
# ------------------------------------------------------------
|
||||
# download.sdgserver.online
|
||||
# ------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
map $scheme $hsts_header {
|
||||
https "max-age=63072000; preload";
|
||||
}
|
||||
|
||||
server {
|
||||
set $forward_scheme http;
|
||||
set $server "?localip?";
|
||||
set $port 3000;
|
||||
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
|
||||
|
||||
server_name download.?domain?;
|
||||
http2 off;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $http_connection;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
|
||||
access_log /data/logs/proxy-host-6_access.log proxy;
|
||||
error_log /data/logs/proxy-host-6_error.log warn;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
location / {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $http_connection;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
|
||||
# Proxy!
|
||||
include conf.d/include/proxy.conf;
|
||||
}
|
||||
|
||||
|
||||
# Custom
|
||||
include /data/nginx/custom/server_proxy[.]conf;
|
||||
}
|
||||