Compare commits
116 Commits
0383b47b8e
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
|
752efbfc3f
|
|||
|
04e1335173
|
|||
|
58624e152e
|
|||
|
4f8d80f3b6
|
|||
|
41cafd1a95
|
|||
|
6ff40bff0e
|
|||
|
d0ebdab064
|
|||
|
00f677e9ee
|
|||
|
3da15dffa2
|
|||
|
412366af2f
|
|||
|
58c6f8027e
|
|||
|
086bab83d3
|
|||
|
0988333f3b
|
|||
|
9d06151ed2
|
|||
|
63ee2aa82b
|
|||
|
49acea31ac
|
|||
|
6b855a5b29
|
|||
|
9d57b8f858
|
|||
|
6d9ba77568
|
|||
|
9c5b00433f
|
|||
|
e241f6ffeb
|
|||
|
188334c850
|
|||
|
6ea4e72e8a
|
|||
|
56c7fcd617
|
|||
|
c9f8a8237d
|
|||
|
bda99dbf5f
|
|||
|
08f36a7a50
|
|||
|
94ebacd84d
|
|||
|
6f86987901
|
|||
|
910ce1b098
|
|||
|
6741f8cac2
|
|||
|
0365832e40
|
|||
|
40515700d1
|
|||
|
c130bfed69
|
|||
|
d19a121005
|
|||
|
d0ff839ff4
|
|||
|
8f5f8df0aa
|
|||
|
9469f23f50
|
|||
|
639dc9065c
|
|||
|
5b5dbd6660
|
|||
|
95aa476c64
|
|||
|
79a8e092eb
|
|||
|
8ab4ed574f
|
|||
|
58bce1e8bf
|
|||
|
75b4f979e3
|
|||
|
c837d5d528
|
|||
|
a8e2d90dc6
|
|||
|
494a7e28a6
|
|||
|
076303d475
|
|||
|
ac054156ef
|
|||
|
2bc34c1aca
|
|||
|
490176ab04
|
|||
|
01b4ee9fd5
|
|||
|
1bafb844f2
|
|||
|
f23f361ceb
|
|||
|
7729ea62b3
|
|||
|
457a57739a
|
|||
|
67ed81fd2e
|
|||
|
2ef8e2c38d
|
|||
|
c8eafb6406
|
|||
|
73d11a0f76
|
|||
|
3628e0a4ac
|
|||
|
20dbf6c0df
|
|||
|
8a2cad16ec
|
|||
|
48330f7ef9
|
|||
|
7703bfa4d5
|
|||
|
ba96f9b84b
|
|||
|
0a33a6150d
|
|||
|
c9be5cedcb
|
|||
|
1fb2493848
|
|||
|
9853214d83
|
|||
|
843d2d12a0
|
|||
|
8f962804a4
|
|||
|
9e485265af
|
|||
|
83bde4b218
|
|||
|
52fca38af9
|
|||
|
4db44bb99e
|
|||
|
0e2ad55eb7
|
|||
|
fca523f013
|
|||
|
4482f85ded
|
|||
|
cd598cce47
|
|||
|
0c20572369
|
|||
|
d2e31bb684
|
|||
|
bbe70647d7
|
|||
|
d6dffc0464
|
|||
|
fb9295c260
|
|||
|
c4ae4561e3
|
|||
|
2902624637
|
|||
|
5049796d07
|
|||
|
5efe4860fc
|
|||
|
499a7e348b
|
|||
|
ed94263050
|
|||
|
4841344d63
|
|||
|
51bcdda5d4
|
|||
|
b38de6ad52
|
|||
|
b642cf7269
|
|||
|
3e3c2fe61e
|
|||
|
04edb8b456
|
|||
|
45c1ea3557
|
|||
|
778c1b3d92
|
|||
|
19806b7b1b
|
|||
|
908a4e0422
|
|||
|
d217309e74
|
|||
|
ce8827ed97
|
|||
|
3b914abf7a
|
|||
|
3266dbafa9
|
|||
|
d7c6e1cf70
|
|||
|
dbbb60cab8
|
|||
|
f54d805371
|
|||
|
b56ece2216
|
|||
|
6eef78a48f
|
|||
|
7cddc059b5
|
|||
|
dd4d97ffc9
|
|||
|
6d28cf7431
|
|||
|
287567a513
|
|||
|
8e9055dcd3
|
@@ -1,10 +1,16 @@
|
|||||||
name: Build Docker
|
name: Build Docker
|
||||||
run-name: Build Docker Images
|
run-name: Build Docker Images
|
||||||
on: [push]
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- '*'
|
||||||
|
- '*/*'
|
||||||
|
tags-ignore:
|
||||||
|
- '*'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
Build Master:
|
Build_Master_ARM:
|
||||||
runs-on: ubuntu-latest
|
runs-on: [ubuntu-latest, arm]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
@@ -21,10 +27,49 @@ jobs:
|
|||||||
run : |
|
run : |
|
||||||
cd master
|
cd master
|
||||||
echo "${{ secrets.DOCKERGIT_TOKEN }}" | docker login git.woodburn.au -u nathanwoodburn --password-stdin
|
echo "${{ secrets.DOCKERGIT_TOKEN }}" | docker login git.woodburn.au -u nathanwoodburn --password-stdin
|
||||||
tag_num=$(git rev-parse --short HEAD)
|
|
||||||
echo "branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}"
|
echo "branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}"
|
||||||
tag=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}
|
tag=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}
|
||||||
tag=${tag//\//-}
|
tag=${tag//\//-}
|
||||||
|
tag_num=${GITHUB_RUN_NUMBER}
|
||||||
|
echo "tag_num=$tag_num"
|
||||||
|
|
||||||
|
if [[ "$tag" == "main" ]]; then
|
||||||
|
tag="latest"
|
||||||
|
else
|
||||||
|
tag_num="${tag}-${tag_num}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
docker build -t hnshosting-master:$tag_num .
|
||||||
|
docker tag hnshosting-master:$tag_num git.woodburn.au/nathanwoodburn/hnshosting-master:$tag_num-arm
|
||||||
|
docker push git.woodburn.au/nathanwoodburn/hnshosting-master:$tag_num-arm
|
||||||
|
docker tag hnshosting-master:$tag_num git.woodburn.au/nathanwoodburn/hnshosting-master:$tag-arm
|
||||||
|
docker push git.woodburn.au/nathanwoodburn/hnshosting-master:$tag-arm
|
||||||
|
|
||||||
|
Build_Master_AMD:
|
||||||
|
runs-on: [ubuntu-latest, amd]
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Install Docker
|
||||||
|
run : |
|
||||||
|
apt-get install ca-certificates curl gnupg
|
||||||
|
install -m 0755 -d /etc/apt/keyrings
|
||||||
|
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
||||||
|
chmod a+r /etc/apt/keyrings/docker.gpg
|
||||||
|
echo "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
|
||||||
|
apt-get update
|
||||||
|
apt-get install docker-ce-cli -y
|
||||||
|
- name: Build Docker image
|
||||||
|
run : |
|
||||||
|
cd master
|
||||||
|
echo "${{ secrets.DOCKERGIT_TOKEN }}" | docker login git.woodburn.au -u nathanwoodburn --password-stdin
|
||||||
|
echo "branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}"
|
||||||
|
tag=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}
|
||||||
|
tag=${tag//\//-}
|
||||||
|
tag_num=${GITHUB_RUN_NUMBER}
|
||||||
|
echo "tag_num=$tag_num"
|
||||||
|
|
||||||
if [[ "$tag" == "main" ]]; then
|
if [[ "$tag" == "main" ]]; then
|
||||||
tag="latest"
|
tag="latest"
|
||||||
else
|
else
|
||||||
@@ -40,10 +85,8 @@ jobs:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Build_Bot_ARM:
|
||||||
|
runs-on: [ubuntu-latest, arm]
|
||||||
Build Bot:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
@@ -60,10 +103,43 @@ jobs:
|
|||||||
run : |
|
run : |
|
||||||
cd discord-bot
|
cd discord-bot
|
||||||
echo "${{ secrets.DOCKERGIT_TOKEN }}" | docker login git.woodburn.au -u nathanwoodburn --password-stdin
|
echo "${{ secrets.DOCKERGIT_TOKEN }}" | docker login git.woodburn.au -u nathanwoodburn --password-stdin
|
||||||
tag_num=$(git rev-parse --short HEAD)
|
|
||||||
echo "branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}"
|
echo "branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}"
|
||||||
tag=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}
|
tag=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}
|
||||||
tag=${tag//\//-}
|
tag=${tag//\//-}
|
||||||
|
tag_num=${GITHUB_RUN_NUMBER}
|
||||||
|
if [[ "$tag" == "main" ]]; then
|
||||||
|
tag="latest"
|
||||||
|
else
|
||||||
|
tag_num="${tag}-${tag_num}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
docker build -t hnshosting-bot:$tag_num .
|
||||||
|
docker tag hnshosting-bot:$tag_num git.woodburn.au/nathanwoodburn/hnshosting-bot:$tag_num-arm
|
||||||
|
docker push git.woodburn.au/nathanwoodburn/hnshosting-bot:$tag_num-arm
|
||||||
|
docker tag hnshosting-bot:$tag_num git.woodburn.au/nathanwoodburn/hnshosting-bot:$tag-arm
|
||||||
|
docker push git.woodburn.au/nathanwoodburn/hnshosting-bot:$tag-arm
|
||||||
|
Build_Bot_AMD:
|
||||||
|
runs-on: [ubuntu-latest, amd]
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Install Docker
|
||||||
|
run : |
|
||||||
|
apt-get install ca-certificates curl gnupg
|
||||||
|
install -m 0755 -d /etc/apt/keyrings
|
||||||
|
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
||||||
|
chmod a+r /etc/apt/keyrings/docker.gpg
|
||||||
|
echo "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
|
||||||
|
apt-get update
|
||||||
|
apt-get install docker-ce-cli -y
|
||||||
|
- name: Build Docker image
|
||||||
|
run : |
|
||||||
|
cd discord-bot
|
||||||
|
echo "${{ secrets.DOCKERGIT_TOKEN }}" | docker login git.woodburn.au -u nathanwoodburn --password-stdin
|
||||||
|
echo "branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}"
|
||||||
|
tag=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}
|
||||||
|
tag=${tag//\//-}
|
||||||
|
tag_num=${GITHUB_RUN_NUMBER}
|
||||||
if [[ "$tag" == "main" ]]; then
|
if [[ "$tag" == "main" ]]; then
|
||||||
tag="latest"
|
tag="latest"
|
||||||
else
|
else
|
||||||
@@ -75,4 +151,3 @@ jobs:
|
|||||||
docker push git.woodburn.au/nathanwoodburn/hnshosting-bot:$tag_num
|
docker push git.woodburn.au/nathanwoodburn/hnshosting-bot:$tag_num
|
||||||
docker tag hnshosting-bot:$tag_num git.woodburn.au/nathanwoodburn/hnshosting-bot:$tag
|
docker tag hnshosting-bot:$tag_num git.woodburn.au/nathanwoodburn/hnshosting-bot:$tag
|
||||||
docker push git.woodburn.au/nathanwoodburn/hnshosting-bot:$tag
|
docker push git.woodburn.au/nathanwoodburn/hnshosting-bot:$tag
|
||||||
|
|
||||||
60
.gitea/workflows/release.yml
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
name: Build Docker for Release
|
||||||
|
run-name: Build Docker Images
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- '*'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
Build Master:
|
||||||
|
runs-on: [ubuntu-latest,arm]
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Install Docker
|
||||||
|
run : |
|
||||||
|
apt-get install ca-certificates curl gnupg
|
||||||
|
install -m 0755 -d /etc/apt/keyrings
|
||||||
|
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
||||||
|
chmod a+r /etc/apt/keyrings/docker.gpg
|
||||||
|
echo "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
|
||||||
|
apt-get update
|
||||||
|
apt-get install docker-ce-cli -y
|
||||||
|
- name: Build Docker image
|
||||||
|
run : |
|
||||||
|
cd master
|
||||||
|
echo "${{ secrets.DOCKERGIT_TOKEN }}" | docker login git.woodburn.au -u nathanwoodburn --password-stdin
|
||||||
|
tag=${GITHUB_REF#refs/tags/}
|
||||||
|
|
||||||
|
docker build -t hnshosting-master:release-$tag .
|
||||||
|
docker tag hnshosting-master:release-$tag git.woodburn.au/nathanwoodburn/hnshosting-master:release-$tag
|
||||||
|
docker push git.woodburn.au/nathanwoodburn/hnshosting-master:release-$tag
|
||||||
|
docker tag hnshosting-master:release-$tag git.woodburn.au/nathanwoodburn/hnshosting-master:release
|
||||||
|
docker push git.woodburn.au/nathanwoodburn/hnshosting-master:release
|
||||||
|
|
||||||
|
Build Bot:
|
||||||
|
runs-on: [ubuntu-latest,arm]
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Install Docker
|
||||||
|
run : |
|
||||||
|
apt-get install ca-certificates curl gnupg
|
||||||
|
install -m 0755 -d /etc/apt/keyrings
|
||||||
|
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
||||||
|
chmod a+r /etc/apt/keyrings/docker.gpg
|
||||||
|
echo "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
|
||||||
|
apt-get update
|
||||||
|
apt-get install docker-ce-cli -y
|
||||||
|
- name: Build Docker image
|
||||||
|
run : |
|
||||||
|
cd discord-bot
|
||||||
|
echo "${{ secrets.DOCKERGIT_TOKEN }}" | docker login git.woodburn.au -u nathanwoodburn --password-stdin
|
||||||
|
tag=${GITHUB_REF#refs/tags/}
|
||||||
|
|
||||||
|
docker build -t hnshosting-bot:release-$tag .
|
||||||
|
docker tag hnshosting-bot:release-$tag git.woodburn.au/nathanwoodburn/hnshosting-bot:release-$tag
|
||||||
|
docker push git.woodburn.au/nathanwoodburn/hnshosting-bot:release-$tag
|
||||||
|
docker tag hnshosting-bot:release-$tag git.woodburn.au/nathanwoodburn/hnshosting-bot:release
|
||||||
|
docker push git.woodburn.au/nathanwoodburn/hnshosting-bot:release
|
||||||
46
README.md
@@ -11,12 +11,24 @@ The master server will be used to manage the worker servers.
|
|||||||
The worker servers will be used to host the wordpress sites.
|
The worker servers will be used to host the wordpress sites.
|
||||||
The bot will be used to provide an easier way to manage the master server.
|
The bot will be used to provide an easier way to manage the master server.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
| Legend | Description |
|
||||||
|
| --- | --- |
|
||||||
|
| Red Connections | Secured by VPN or over LAN ONLY. (NOT API SECURED) |
|
||||||
|
| Yellow Connections | HTTP/HTTPS public traffic |
|
||||||
|
|
||||||
|
## Features
|
||||||
|
- [x] Add new worker server to master server pool
|
||||||
|
- [x] Create wordpress site on random worker server
|
||||||
|
- [x] Optional Free mode (see Bot section)
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
After installing the master and discord bot you can use the following commands (as bot owner).
|
After installing the master and discord bot you can use the following commands (as bot owner).
|
||||||
|
|
||||||
```
|
```
|
||||||
/addworker <ip> <name> | add a worker to the master server pool (Make sure the master can access port 5000 on the worker, and don't allow anyone else to access it)
|
/addworker <ip> <private ip> <name> | add a worker to the master server pool
|
||||||
/listworkers | list all workers
|
/listworkers | list all workers
|
||||||
/licence | Creates a licence key (valid for 1 wp site)
|
/licence | Creates a licence key (valid for 1 wp site)
|
||||||
```
|
```
|
||||||
@@ -35,7 +47,7 @@ General commands (as anyone)
|
|||||||
Docker is the easiest way to install the master server.
|
Docker is the easiest way to install the master server.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
docker run -d -p 5000:5000 -e LICENCE-API=your-api-key -e WORKER_KEY=your-api-key --name hnshosting-master git.woodburn.au/nathanwoodburn/hnshosting-master:latest -v ./data:/data
|
docker run -d -p 5000:5000 -e LICENCE_KEY=your-api-key -e WORKER_KEY=your-api-key -e ADMIN_KEY=admin-key --name hnshosting-master git.woodburn.au/nathanwoodburn/hnshosting-master:latest -v ./data:/data
|
||||||
```
|
```
|
||||||
You can also mount a docker volume to /data to store the files instead of mounting a host directory.
|
You can also mount a docker volume to /data to store the files instead of mounting a host directory.
|
||||||
|
|
||||||
@@ -74,15 +86,22 @@ cd hnshosting-wp/worker
|
|||||||
chmod +x install.sh
|
chmod +x install.sh
|
||||||
./install.sh
|
./install.sh
|
||||||
```
|
```
|
||||||
Then to start the worker api server
|
Just press enter when it shows any prompts.
|
||||||
|
|
||||||
|
Start the worker api server using
|
||||||
```sh
|
```sh
|
||||||
screen -dmS hnshosting-worker python3 main.py
|
screen -dmS hnshosting-worker python3 main.py
|
||||||
```
|
```
|
||||||
|
|
||||||
Add worker to master server:
|
Add worker to master server pool:
|
||||||
|
The master server will need to be able to access port 5000 on the worker server over the PRIVATE ip. This is not secured by the api key so make sure you don't allow anyone else to access it.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
curl -X POST http://master-server-ip:5000/add-worker?worker=worker-name&ip=worker-server-ip -H "key: api-key"
|
curl -X POST http://master-server-ip:5000/add-worker?worker=worker-name&ip=worker-server-ip&priv=worker-server-private-ip -H "key: api-key"
|
||||||
|
```
|
||||||
|
Alternatively you can use the discord bot to add the worker to the master server pool.
|
||||||
|
```
|
||||||
|
/addworker <ip> <private ip> <name>
|
||||||
```
|
```
|
||||||
|
|
||||||
## Discord bot install
|
## Discord bot install
|
||||||
@@ -91,3 +110,20 @@ Docker install
|
|||||||
```sh
|
```sh
|
||||||
docker run -d -e MASTER_IP=<MASTER SERVER IP> -e DISCORD_TOKEN=<YOUR-BOT-TOKEN> -e LICENCE_KEY=your-api-key -e WORKER_KEY=your-api-key --name hnshosting-bot git.woodburn.au/nathanwoodburn/hnshosting-bot:latest
|
docker run -d -e MASTER_IP=<MASTER SERVER IP> -e DISCORD_TOKEN=<YOUR-BOT-TOKEN> -e LICENCE_KEY=your-api-key -e WORKER_KEY=your-api-key --name hnshosting-bot git.woodburn.au/nathanwoodburn/hnshosting-bot:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Enable the free mode by setting the following environment variable.
|
||||||
|
This will allow you to create a wordpress site without using a licence key using the /createsite command.
|
||||||
|
```
|
||||||
|
FREE_MODE: true
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Hip2
|
||||||
|
HIP2 allows sending HNS to a domain.
|
||||||
|
To enable HIP2 on your wordpress site you should
|
||||||
|
|
||||||
|
1. Download the [HIP2 plugin](https://git.woodburn.au/nathanwoodburn/hnshosting-wp/raw/branch/main/assets/hns-wallet-plugin.zip)
|
||||||
|
2. Upload the plugin to your wordpress site
|
||||||
|
3. Activate the plugin
|
||||||
|
4. Go to the settings page and enter your HNS wallet address
|
||||||
|
5. Ensure it works by settings the permalink to post name and saving
|
||||||
BIN
assets/hns-wallet-plugin.zip
Normal file
BIN
assets/overview.png
Normal file
|
After Width: | Height: | Size: 144 KiB |
@@ -3,6 +3,8 @@ from dotenv import load_dotenv
|
|||||||
import discord
|
import discord
|
||||||
from discord import app_commands
|
from discord import app_commands
|
||||||
import requests
|
import requests
|
||||||
|
import asyncio
|
||||||
|
import re
|
||||||
|
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
TOKEN = os.getenv('DISCORD_TOKEN')
|
TOKEN = os.getenv('DISCORD_TOKEN')
|
||||||
@@ -12,18 +14,23 @@ Master_Port = os.getenv('MASTER_PORT')
|
|||||||
if Master_Port == None:
|
if Master_Port == None:
|
||||||
Master_Port = "5000"
|
Master_Port = "5000"
|
||||||
|
|
||||||
FREE_LICENCE = os.getenv('FREE_LICENCE')
|
FREE_LICENCE = os.getenv('FREE_MODE')
|
||||||
if FREE_LICENCE == None:
|
if FREE_LICENCE == None:
|
||||||
FREE_LICENCE = False
|
FREE_LICENCE = False
|
||||||
|
else:
|
||||||
|
if FREE_LICENCE.lower() == "true":
|
||||||
|
FREE_LICENCE = True
|
||||||
|
else:
|
||||||
|
FREE_LICENCE = False
|
||||||
|
|
||||||
intents = discord.Intents.default()
|
intents = discord.Intents.default()
|
||||||
client = discord.Client(intents=intents)
|
client = discord.Client(intents=intents)
|
||||||
tree = app_commands.CommandTree(client)
|
tree = app_commands.CommandTree(client)
|
||||||
|
|
||||||
@tree.command(name="addworker", description="Adds a worker to the master server")
|
@tree.command(name="addworker", description="Adds a worker to the master server")
|
||||||
async def addworker(ctx, ip: str, name: str):
|
async def addworker(ctx, ip: str,privateip: str, name: str):
|
||||||
if ctx.user.id == ADMINID:
|
if ctx.user.id == ADMINID:
|
||||||
r = requests.post(f"http://{Master_IP}:{Master_Port}/add-worker?worker={name}&ip={ip}",headers={"key":os.getenv('WORKER_KEY')})
|
r = requests.post(f"http://{Master_IP}:{Master_Port}/add-worker?worker={name}&ip={ip}&priv={privateip}",headers={"key":os.getenv('WORKER_KEY')})
|
||||||
if r.status_code == 200:
|
if r.status_code == 200:
|
||||||
await ctx.response.send_message(f"Worker {name} added to the master server",ephemeral=True)
|
await ctx.response.send_message(f"Worker {name} added to the master server",ephemeral=True)
|
||||||
else:
|
else:
|
||||||
@@ -45,13 +52,13 @@ async def listworkers(ctx):
|
|||||||
await ctx.response.send_message(f"Error listing workers\n" + r.text,ephemeral=True)
|
await ctx.response.send_message(f"Error listing workers\n" + r.text,ephemeral=True)
|
||||||
else:
|
else:
|
||||||
await ctx.response.send_message("You do not have permission to use this command",ephemeral=True)
|
await ctx.response.send_message("You do not have permission to use this command",ephemeral=True)
|
||||||
|
update_bot_status()
|
||||||
|
|
||||||
@tree.command(name="licence", description="Gets a licence key")
|
@tree.command(name="licence", description="Gets a licence key")
|
||||||
async def license(ctx):
|
async def license(ctx):
|
||||||
if ctx.user.id != ADMINID:
|
if ctx.user.id != ADMINID:
|
||||||
if FREE_LICENCE == False: # If free licences are enabled then anyone can get a licence
|
await ctx.response.send_message("You do not have permission to use this command",ephemeral=True)
|
||||||
await ctx.response.send_message("You do not have permission to use this command",ephemeral=True)
|
return
|
||||||
return
|
|
||||||
|
|
||||||
r = requests.post(f"http://{Master_IP}:{Master_Port}/add-licence",headers={"key":os.getenv('LICENCE_KEY')})
|
r = requests.post(f"http://{Master_IP}:{Master_Port}/add-licence",headers={"key":os.getenv('LICENCE_KEY')})
|
||||||
if r.status_code == 200:
|
if r.status_code == 200:
|
||||||
@@ -64,16 +71,59 @@ async def license(ctx):
|
|||||||
await ctx.response.send_message(f"Error getting license\n" + r.text,ephemeral=True)
|
await ctx.response.send_message(f"Error getting license\n" + r.text,ephemeral=True)
|
||||||
|
|
||||||
@tree.command(name="createsite", description="Create a new WordPress site")
|
@tree.command(name="createsite", description="Create a new WordPress site")
|
||||||
async def createsite(ctx, domain: str, licence: str):
|
async def createsite(ctx, domain: str, licence: str = None):
|
||||||
|
# Verify domain is valid
|
||||||
|
if domain == None:
|
||||||
|
await ctx.response.send_message("You must specify a domain",ephemeral=True)
|
||||||
|
return
|
||||||
|
if "http://" in domain or "https://" in domain:
|
||||||
|
await ctx.response.send_message("You must specify a domain without http:// or https://",ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
domain = domain.lower().strip()
|
||||||
|
# Regex for a domain (or a tld)
|
||||||
|
if not re.match(r'^[a-z0-9-]+(\.[a-z0-9-]+)*$', domain):
|
||||||
|
await ctx.response.send_message("You must specify a valid domain",ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
if FREE_LICENCE == True: # If free licences are enabled then auto generate a licence
|
||||||
|
r = requests.post(f"http://{Master_IP}:{Master_Port}/add-licence",headers={"key":os.getenv('LICENCE_KEY')})
|
||||||
|
if r.status_code == 200:
|
||||||
|
json = r.json()
|
||||||
|
if json['success'] == "true":
|
||||||
|
licence = json['licence_key']
|
||||||
|
else:
|
||||||
|
await ctx.response.send_message(f"Error getting license\n" + json['error'])
|
||||||
|
return
|
||||||
|
|
||||||
r = requests.post(f"http://{Master_IP}:{Master_Port}/new-site?domain={domain}",headers={"key":licence})
|
r = requests.post(f"http://{Master_IP}:{Master_Port}/new-site?domain={domain}",headers={"key":licence})
|
||||||
if r.status_code == 200:
|
if r.status_code == 200:
|
||||||
json = r.json()
|
json = r.json()
|
||||||
if json['success'] == "true":
|
if json['success'] == "true":
|
||||||
await ctx.response.send_message(f"Site {domain} creating...\nPlease wait a few minutes and then send /siteinfo domain:{domain}")
|
await ctx.response.send_message(f"Site https://{domain} creating...\nI'll send you a message when it's ready")
|
||||||
|
|
||||||
|
ready = False
|
||||||
|
while ready == False:
|
||||||
|
ready = await check_site_ready(domain)
|
||||||
|
if ready == False:
|
||||||
|
await asyncio.sleep(5)
|
||||||
|
|
||||||
|
r = requests.get(f"http://{Master_IP}:{Master_Port}/site-info?domain={domain}")
|
||||||
|
json = r.json()
|
||||||
|
if json['success'] == "true":
|
||||||
|
if json['ip'] == '143.42.45.236':
|
||||||
|
await ctx.user.send(f"Site https://{domain} is ready!\nHere is the site info for {json['domain']}\nALIAS: `01.hnshosting.au`\nTLSA: `{json['tlsa']}`\nMake sure you put the TLSA in either `_443._tcp.{domain}` or `*.{domain}`")
|
||||||
|
else:
|
||||||
|
await ctx.user.send(f"Site https://{domain} is ready!\nHere is the site info for {json['domain']}\nA: `{json['ip']}`\nTLSA: `{json['tlsa']}`\nMake sure you put the TLSA in either `_443._tcp.{domain}` or `*.{domain}`")
|
||||||
|
else:
|
||||||
|
await ctx.user.send(f"Error getting site info\n" + json['error'])
|
||||||
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
await ctx.response.send_message(f"Error creating site\n" + json['error'])
|
await ctx.response.send_message(f"Error creating site\n" + json['error'])
|
||||||
else:
|
else:
|
||||||
await ctx.response.send_message(f"Error creating site\n" + r.text)
|
await ctx.response.send_message(f"Error creating site\n" + r.text)
|
||||||
|
update_bot_status()
|
||||||
|
|
||||||
|
|
||||||
@tree.command(name="siteinfo", description="Get info about a WordPress site")
|
@tree.command(name="siteinfo", description="Get info about a WordPress site")
|
||||||
@@ -88,12 +138,37 @@ async def siteinfo(ctx, domain: str):
|
|||||||
else:
|
else:
|
||||||
await ctx.response.send_message(f"Error getting site info\n" + r.text)
|
await ctx.response.send_message(f"Error getting site info\n" + r.text)
|
||||||
|
|
||||||
|
async def check_site_ready(domain):
|
||||||
|
r = requests.get(f"http://{Master_IP}:{Master_Port}/site-info?domain={domain}")
|
||||||
|
if r.status_code == 200:
|
||||||
|
json = r.json()
|
||||||
|
if json['success'] == "true":
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_site_count():
|
||||||
|
r = requests.get(f"http://{Master_IP}:{Master_Port}/site-count")
|
||||||
|
if r.status_code == 200:
|
||||||
|
return r.text
|
||||||
|
else:
|
||||||
|
return "Error getting site count\n" + r.text
|
||||||
|
|
||||||
|
def update_bot_status():
|
||||||
|
site_count = get_site_count()
|
||||||
|
client.loop.create_task(client.change_presence(activity=discord.Activity(type=discord.ActivityType.watching, name="over " + site_count + " wordpress sites")))
|
||||||
|
|
||||||
# When the bot is ready
|
# When the bot is ready
|
||||||
@client.event
|
@client.event
|
||||||
async def on_ready():
|
async def on_ready():
|
||||||
global ADMINID
|
global ADMINID
|
||||||
ADMINID = client.application.owner.id
|
ADMINID = client.application.owner.id
|
||||||
await tree.sync()
|
await tree.sync()
|
||||||
await client.loop.create_task(client.change_presence(activity=discord.Activity(type=discord.ActivityType.watching, name="over HNSHosting wordpress")))
|
|
||||||
|
# Get the number of sites
|
||||||
|
site_count = get_site_count()
|
||||||
|
await client.loop.create_task(client.change_presence(activity=discord.Activity(type=discord.ActivityType.watching, name="over " + site_count + " wordpress sites")))
|
||||||
|
|
||||||
client.run(TOKEN)
|
client.run(TOKEN)
|
||||||
10
master/assets/css/index.css
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
html {
|
||||||
|
background-color: black;
|
||||||
|
color: white;
|
||||||
|
font-family: 'Roboto', sans-serif;
|
||||||
|
font-size: 16px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
li {
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
BIN
master/assets/img/favicon.png
Normal file
|
After Width: | Height: | Size: 6.5 KiB |
550
master/main.py
@@ -1,4 +1,4 @@
|
|||||||
from flask import Flask, request, jsonify
|
from flask import Flask, make_response, redirect, request, jsonify, render_template, send_from_directory
|
||||||
import dotenv
|
import dotenv
|
||||||
import os
|
import os
|
||||||
import requests
|
import requests
|
||||||
@@ -10,12 +10,14 @@ dotenv.load_dotenv()
|
|||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
logins = []
|
||||||
|
|
||||||
# API add license key (requires API key in header)
|
# API add license key (requires API key in header)
|
||||||
@app.route('/add-licence', methods=['POST'])
|
@app.route('/add-licence', methods=['POST'])
|
||||||
def add_license():
|
def add_license():
|
||||||
# Get API header
|
# Get API header
|
||||||
api_key = request.headers.get('key')
|
api_key = request.headers.get('key')
|
||||||
if api_key != os.getenv('LICENCE-API'):
|
if api_key != os.getenv('LICENCE_KEY'):
|
||||||
return jsonify({'error': 'Invalid API key', 'success': 'false'})
|
return jsonify({'error': 'Invalid API key', 'success': 'false'})
|
||||||
|
|
||||||
# Generate licence key
|
# Generate licence key
|
||||||
@@ -37,14 +39,22 @@ def new_site():
|
|||||||
|
|
||||||
# Verify both API key and domain exist
|
# Verify both API key and domain exist
|
||||||
if api_key == None:
|
if api_key == None:
|
||||||
return jsonify({'error': 'Missing API key', 'success': 'false'})
|
return jsonify({'error': 'No licence provided', 'success': 'false'})
|
||||||
|
|
||||||
if domain == None:
|
if domain == None:
|
||||||
return jsonify({'error': 'Missing domain', 'success': 'false'})
|
return jsonify({'error': 'Missing domain', 'success': 'false'})
|
||||||
|
|
||||||
# Check if API key is a valid site key
|
# Check if API key is a valid site key
|
||||||
if api_key not in open('/data/licence_key.txt', 'r').read():
|
key_file = open('/data/licence_key.txt', 'r')
|
||||||
return jsonify({'error': 'Invalid API key', 'success': 'false'})
|
valid_key = False
|
||||||
|
for line in key_file.readlines():
|
||||||
|
if api_key == line.strip('\n'):
|
||||||
|
valid_key = True
|
||||||
|
break
|
||||||
|
key_file.close()
|
||||||
|
if not valid_key:
|
||||||
|
return jsonify({'error': 'Invalid licence', 'success': 'false'})
|
||||||
|
|
||||||
|
|
||||||
# Check if domain already exists
|
# Check if domain already exists
|
||||||
if site_exists(domain):
|
if site_exists(domain):
|
||||||
@@ -107,9 +117,10 @@ def new_site():
|
|||||||
def add_worker():
|
def add_worker():
|
||||||
worker=request.args.get('worker')
|
worker=request.args.get('worker')
|
||||||
worker_IP=request.args.get('ip')
|
worker_IP=request.args.get('ip')
|
||||||
|
worker_PRIV=request.args.get('priv')
|
||||||
# Get API header
|
# Get API header
|
||||||
api_key = request.headers.get('key')
|
api_key = request.headers.get('key')
|
||||||
if api_key == None or worker == None or worker_IP == None:
|
if api_key == None or worker == None or worker_IP == None or worker_PRIV == None:
|
||||||
return jsonify({'error': 'Invalid API key or worker info', 'success': 'false'})
|
return jsonify({'error': 'Invalid API key or worker info', 'success': 'false'})
|
||||||
if api_key != os.getenv('WORKER_KEY'):
|
if api_key != os.getenv('WORKER_KEY'):
|
||||||
return jsonify({'error': 'Invalid API key', 'success': 'false'})
|
return jsonify({'error': 'Invalid API key', 'success': 'false'})
|
||||||
@@ -130,11 +141,11 @@ def add_worker():
|
|||||||
|
|
||||||
# Add worker to file
|
# Add worker to file
|
||||||
workers_file = open('/data/workers.txt', 'a')
|
workers_file = open('/data/workers.txt', 'a')
|
||||||
workers_file.write(worker + ":" + worker_IP + '\n')
|
workers_file.write(worker + ":" + worker_PRIV + ":"+ worker_IP + '\n')
|
||||||
workers_file.close()
|
workers_file.close()
|
||||||
|
|
||||||
online=True
|
online=True
|
||||||
resp=requests.get("http://"+worker_IP + ":5000/ping",timeout=2)
|
resp=requests.get("http://"+worker_PRIV + ":5000/ping",timeout=2)
|
||||||
if (resp.status_code != 200):
|
if (resp.status_code != 200):
|
||||||
online=False
|
online=False
|
||||||
|
|
||||||
@@ -168,22 +179,34 @@ def list_workers():
|
|||||||
for worker in workers:
|
for worker in workers:
|
||||||
# Check worker status
|
# Check worker status
|
||||||
if not worker.__contains__(':'):
|
if not worker.__contains__(':'):
|
||||||
return jsonify({'error': 'No workers available', 'success': 'false'})
|
continue
|
||||||
|
|
||||||
online=True
|
online=True
|
||||||
resp=requests.get("http://"+worker.split(':')[1].strip('\n') + ":5000/status",timeout=2)
|
try:
|
||||||
if (resp.status_code != 200):
|
resp=requests.get("http://"+worker.split(':')[1].strip('\n') + ":5000/status",timeout=2)
|
||||||
online=False
|
|
||||||
worker_list.append({'worker': worker.split(':')[0],'ip': worker.split(':')[1].strip('\n'), 'online': online, 'sites': 0, 'ready': 0})
|
|
||||||
continue
|
|
||||||
sites = resp.json()['num_sites']
|
|
||||||
worker_list.append({'worker': worker.split(':')[0],'ip': worker.split(':')[1].strip('\n'), 'online': online, 'sites': sites, 'ready': 1})
|
|
||||||
|
|
||||||
|
if (resp.status_code != 200):
|
||||||
|
online=False
|
||||||
|
worker_list.append({'worker': worker.split(':')[0],'ip': worker.split(':')[2].strip('\n'), 'online': online, 'sites': 0, 'status': 'offline'})
|
||||||
|
continue
|
||||||
|
sites = resp.json()['num_sites']
|
||||||
|
availability = resp.json()['availability']
|
||||||
|
if availability == True:
|
||||||
|
worker_list.append({'worker': worker.split(':')[0],'ip': worker.split(':')[2].strip('\n'), 'online': online, 'sites': sites, 'status': 'ready'})
|
||||||
|
else:
|
||||||
|
worker_list.append({'worker': worker.split(':')[0],'ip': worker.split(':')[2].strip('\n'), 'online': online, 'sites': sites, 'status': 'full'})
|
||||||
|
except:
|
||||||
|
worker_list.append({'worker': worker.split(':')[0],'ip': worker.split(':')[2].strip('\n'), 'online': 'False', 'sites': 0, 'status': 'offline'})
|
||||||
|
continue
|
||||||
|
|
||||||
|
if len(worker_list) == 0:
|
||||||
|
return jsonify({'error': 'No workers available', 'success': 'false'})
|
||||||
return jsonify({'success': 'true', 'workers': worker_list})
|
return jsonify({'success': 'true', 'workers': worker_list})
|
||||||
|
|
||||||
@app.route('/site-info', methods=['GET'])
|
@app.route('/site-info', methods=['GET'])
|
||||||
def site_status():
|
def site_status():
|
||||||
domain = request.args.get('domain')
|
domain = request.args.get('domain')
|
||||||
|
domain = domain.lower()
|
||||||
if domain == None:
|
if domain == None:
|
||||||
return jsonify({'error': 'Invalid domain', 'success': 'false'})
|
return jsonify({'error': 'Invalid domain', 'success': 'false'})
|
||||||
|
|
||||||
@@ -197,22 +220,23 @@ def site_status():
|
|||||||
return jsonify({'error': 'Domain does not exist', 'success': 'false'})
|
return jsonify({'error': 'Domain does not exist', 'success': 'false'})
|
||||||
|
|
||||||
# Get worker ip
|
# Get worker ip
|
||||||
ip = workerIP(worker)
|
ip = workerIP_PRIV(worker)
|
||||||
|
|
||||||
# Get TLSA record
|
# Get TLSA record
|
||||||
resp=requests.get("http://"+ip + ":5000/tlsa?domain=" + domain,timeout=2)
|
resp=requests.get("http://"+ip + ":5000/tlsa?domain=" + domain,timeout=2)
|
||||||
json = resp.json()
|
json = resp.json()
|
||||||
|
publicIP = workerIP(worker)
|
||||||
|
|
||||||
if "tlsa" in json:
|
if "tlsa" in json:
|
||||||
tlsa = json['tlsa']
|
tlsa = json['tlsa']
|
||||||
return jsonify({'success': 'true', 'domain': domain, 'ip': ip, 'tlsa': tlsa})
|
return jsonify({'success': 'true', 'domain': domain, 'ip': publicIP, 'tlsa': tlsa})
|
||||||
else:
|
else:
|
||||||
return jsonify({'success': 'false', 'domain': domain, 'ip': ip, 'tlsa': 'none','error': 'No TLSA record found'})
|
return jsonify({'success': 'false', 'domain': domain, 'ip': publicIP, 'tlsa': 'none','error': 'No TLSA record found'})
|
||||||
|
|
||||||
|
|
||||||
@app.route('/tlsa', methods=['GET'])
|
@app.route('/tlsa', methods=['GET'])
|
||||||
def tlsa():
|
def tlsa():
|
||||||
domain = request.args.get('domain')
|
domain = request.args.get('domain')
|
||||||
|
domain = domain.lower()
|
||||||
if domain == None:
|
if domain == None:
|
||||||
return jsonify({'error': 'Invalid domain', 'success': 'false'})
|
return jsonify({'error': 'Invalid domain', 'success': 'false'})
|
||||||
|
|
||||||
@@ -226,7 +250,7 @@ def tlsa():
|
|||||||
return jsonify({'error': 'Domain does not exist', 'success': 'false'})
|
return jsonify({'error': 'Domain does not exist', 'success': 'false'})
|
||||||
|
|
||||||
# Get worker ip
|
# Get worker ip
|
||||||
ip = workerIP(worker)
|
ip = workerIP_PRIV(worker)
|
||||||
|
|
||||||
# Get TLSA record
|
# Get TLSA record
|
||||||
resp=requests.get("http://"+ip + ":5000/tlsa?domain=" + domain,timeout=2)
|
resp=requests.get("http://"+ip + ":5000/tlsa?domain=" + domain,timeout=2)
|
||||||
@@ -253,7 +277,14 @@ def stripeapi():
|
|||||||
return jsonify({'success': 'false'})
|
return jsonify({'success': 'false'})
|
||||||
|
|
||||||
if event.type == 'payment_intent.succeeded':
|
if event.type == 'payment_intent.succeeded':
|
||||||
|
# Only for payments for licences
|
||||||
payment_intent = event.data.object
|
payment_intent = event.data.object
|
||||||
|
if payment_intent['amount'] != 1000:
|
||||||
|
return jsonify({'success': 'true'})
|
||||||
|
|
||||||
|
if payment_intent['description'] != "Subscription creation":
|
||||||
|
return jsonify({'success': 'true'})
|
||||||
|
|
||||||
# Get email
|
# Get email
|
||||||
email = payment_intent['receipt_email']
|
email = payment_intent['receipt_email']
|
||||||
# Create licence key
|
# Create licence key
|
||||||
@@ -277,7 +308,7 @@ def stripeapi():
|
|||||||
message = "From: " + from_email + "\nTo: " + email + \
|
message = "From: " + from_email + "\nTo: " + email + \
|
||||||
"\nSubject: Your Licence key\n\nHello,\n\n"\
|
"\nSubject: Your Licence key\n\nHello,\n\n"\
|
||||||
+"This email contains your licence key for your new wordpress site.\n" \
|
+"This email contains your licence key for your new wordpress site.\n" \
|
||||||
+"You can redeem this key via the discord bot or api.\n\n"\
|
+"You can redeem this key via the discord bot or at https://hnshosting.au/register\n\n"\
|
||||||
+"Your licence key is: " + licence_key +"\nThanks,\nHNSHosting"
|
+"Your licence key is: " + licence_key +"\nThanks,\nHNSHosting"
|
||||||
|
|
||||||
server.sendmail(from_email, email, message)
|
server.sendmail(from_email, email, message)
|
||||||
@@ -337,7 +368,7 @@ def site_worker(domain):
|
|||||||
sites_file.close()
|
sites_file.close()
|
||||||
return worker
|
return worker
|
||||||
|
|
||||||
def workerIP(worker):
|
def workerIP_PRIV(worker):
|
||||||
# If file doesn't exist, create it
|
# If file doesn't exist, create it
|
||||||
try:
|
try:
|
||||||
workers_file = open('/data/workers.txt', 'r')
|
workers_file = open('/data/workers.txt', 'r')
|
||||||
@@ -355,6 +386,479 @@ def workerIP(worker):
|
|||||||
workers_file.close()
|
workers_file.close()
|
||||||
return ip
|
return ip
|
||||||
|
|
||||||
|
def workerIP(worker):
|
||||||
|
# If file doesn't exist, create it
|
||||||
|
try:
|
||||||
|
workers_file = open('/data/workers.txt', 'r')
|
||||||
|
except FileNotFoundError:
|
||||||
|
workers_file = open('/data/workers.txt', 'w')
|
||||||
|
workers_file.close()
|
||||||
|
workers_file = open('/data/workers.txt', 'r')
|
||||||
|
|
||||||
|
ip = None
|
||||||
|
for line in workers_file.readlines():
|
||||||
|
if worker == line.split(':')[0]:
|
||||||
|
ip = line.split(':')[2].strip('\n')
|
||||||
|
break
|
||||||
|
|
||||||
|
workers_file.close()
|
||||||
|
return ip
|
||||||
|
|
||||||
|
|
||||||
|
# Home page
|
||||||
|
@app.route('/')
|
||||||
|
def home():
|
||||||
|
# Show index template
|
||||||
|
# Get site info
|
||||||
|
sites = []
|
||||||
|
try:
|
||||||
|
sites_file = open('/data/sites.txt', 'r')
|
||||||
|
sites = sites_file.readlines()
|
||||||
|
sites_file.close()
|
||||||
|
except FileNotFoundError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
return render_template('index.html', site_count = str(len(sites)))
|
||||||
|
|
||||||
|
# Register page
|
||||||
|
@app.route('/register', methods=['GET'])
|
||||||
|
def register():
|
||||||
|
buy_licence_link = os.getenv('BUY_LICENCE_LINK')
|
||||||
|
|
||||||
|
# Show register template
|
||||||
|
return render_template('register.html', buy_licence_link=buy_licence_link, ERROR_MESSAGE="")
|
||||||
|
|
||||||
|
@app.route('/register', methods=['POST'])
|
||||||
|
def register_post():
|
||||||
|
buy_licence_link = os.getenv('BUY_LICENCE_LINK')
|
||||||
|
if 'licence' not in request.form:
|
||||||
|
return render_template('register.html', buy_licence_link=buy_licence_link, ERROR_MESSAGE="No licence key provided")
|
||||||
|
|
||||||
|
licence_key = request.form['licence']
|
||||||
|
# Check if licence key is valid
|
||||||
|
key_file = open('/data/licence_key.txt', 'r')
|
||||||
|
valid_key = False
|
||||||
|
for line in key_file.readlines():
|
||||||
|
if licence_key == line.strip('\n'):
|
||||||
|
valid_key = True
|
||||||
|
break
|
||||||
|
key_file.close()
|
||||||
|
if not valid_key:
|
||||||
|
return render_template('register.html', buy_licence_link=buy_licence_link, ERROR_MESSAGE="Invalid licence key")
|
||||||
|
|
||||||
|
# Get domain
|
||||||
|
domain = request.form['domain']
|
||||||
|
if domain == None:
|
||||||
|
return render_template('register.html', buy_licence_link=buy_licence_link, ERROR_MESSAGE="No domain provided")
|
||||||
|
# Check if domain already exists
|
||||||
|
if site_exists(domain):
|
||||||
|
return render_template('register.html', buy_licence_link=buy_licence_link, ERROR_MESSAGE="Domain already exists")
|
||||||
|
|
||||||
|
# Check if domain contains http:// or https://
|
||||||
|
if domain.startswith("http://") or domain.startswith("https://"):
|
||||||
|
return render_template('register.html', buy_licence_link=buy_licence_link, ERROR_MESSAGE="Domain should not contain http:// or https://")
|
||||||
|
|
||||||
|
# Set domain to lowercase
|
||||||
|
domain = domain.lower()
|
||||||
|
|
||||||
|
# Check if worker file exists
|
||||||
|
workers = None
|
||||||
|
try:
|
||||||
|
worker_file = open('/data/workers.txt', 'r')
|
||||||
|
workers = worker_file.readlines()
|
||||||
|
worker_file.close()
|
||||||
|
except FileNotFoundError:
|
||||||
|
return render_template('register.html', buy_licence_link=buy_licence_link, ERROR_MESSAGE="No workers available\nPlease contact support")
|
||||||
|
|
||||||
|
# Get a worker that has available slots
|
||||||
|
worker = None
|
||||||
|
for line in workers:
|
||||||
|
if not line.__contains__(':'):
|
||||||
|
continue
|
||||||
|
ip = line.split(':')[1].strip('\n')
|
||||||
|
resp=requests.get("http://"+ip + ":5000/status",timeout=2)
|
||||||
|
if (resp.status_code == 200):
|
||||||
|
if resp.json()['availability'] == True:
|
||||||
|
worker = line
|
||||||
|
break
|
||||||
|
|
||||||
|
if worker == None:
|
||||||
|
return render_template('register.html', buy_licence_link=buy_licence_link, ERROR_MESSAGE="No workers available\nPlease contact support")
|
||||||
|
|
||||||
|
# Delete licence key
|
||||||
|
key_file = open('/data/licence_key.txt', 'r')
|
||||||
|
lines = key_file.readlines()
|
||||||
|
key_file.close()
|
||||||
|
key_file = open('/data/licence_key.txt', 'w')
|
||||||
|
for line in lines:
|
||||||
|
if line.strip("\n") != licence_key:
|
||||||
|
key_file.write(line)
|
||||||
|
key_file.close()
|
||||||
|
|
||||||
|
# Add domain to file
|
||||||
|
sites_file = open('/data/sites.txt', 'a')
|
||||||
|
sites_file.write(domain + ':' + worker.split(':')[0] + '\n')
|
||||||
|
sites_file.close()
|
||||||
|
|
||||||
|
# Send worker request
|
||||||
|
requests.post("http://"+ worker.split(':')[1].strip('\n') + ":5000/new-site?domain=" + domain)
|
||||||
|
|
||||||
|
return redirect('/success?domain=' + domain + '&status=creating')
|
||||||
|
|
||||||
|
@app.route('/success')
|
||||||
|
@app.route('/info')
|
||||||
|
def success():
|
||||||
|
if 'domain' not in request.args:
|
||||||
|
return redirect('/')
|
||||||
|
domain = request.args.get('domain')
|
||||||
|
domain = domain.lower()
|
||||||
|
if not site_exists(domain):
|
||||||
|
return render_template('success.html', title="Your site is installing.<br>Please wait...",message="")
|
||||||
|
|
||||||
|
if 'status' not in request.args:
|
||||||
|
# Get worker
|
||||||
|
worker = site_worker(domain)
|
||||||
|
if worker == None:
|
||||||
|
return render_template('success.html', title="Your site is installing.<br>Please wait...",message="Error: Domain does not exist<br>Please contact support")
|
||||||
|
# Get worker ip
|
||||||
|
ip = workerIP_PRIV(worker)
|
||||||
|
|
||||||
|
# Get TLSA record
|
||||||
|
resp=requests.get("http://"+ip + ":5000/tlsa?domain=" + domain,timeout=2)
|
||||||
|
json = resp.json()
|
||||||
|
publicIP = workerIP(worker)
|
||||||
|
|
||||||
|
if "tlsa" in json:
|
||||||
|
tlsa = json['tlsa']
|
||||||
|
return render_template('success.html', title="Your site is ready!",message="Success<br>Domain: <code>" + domain + "</code><br>IP: <code>" + publicIP + "</code><br>TLSA: <code>" + tlsa + "</code><br>Make sure to add the TLSA record to <code>_443._tcp." + domain + "</code> or <code>*." + domain + "</code>")
|
||||||
|
else:
|
||||||
|
return render_template('success.html', title="Your site is installing.<br>Please wait...",message="Domain: <code>" + domain + "</code><br>IP: <code>" + publicIP + "</code><br>TLSA: Pending<br>No TLSA record found")
|
||||||
|
|
||||||
|
elif request.args.get('status') == 'creating':
|
||||||
|
return render_template('success.html')
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/site-count')
|
||||||
|
def site_count_route():
|
||||||
|
return str(get_sites_count())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Admin page
|
||||||
|
@app.route('/admin')
|
||||||
|
def admin():
|
||||||
|
# Check if logged in
|
||||||
|
login_key = request.cookies.get('login_key')
|
||||||
|
|
||||||
|
if login_key == None:
|
||||||
|
return "<h1>Admin</h1><br><form action='/login' method='POST'><input type='password' name='password'><input type='submit' value='Login'></form>"
|
||||||
|
if login_key not in logins:
|
||||||
|
return "<h1>Admin</h1><br><form action='/login' method='POST'><input type='password' name='password'><input type='submit' value='Login'></form>"
|
||||||
|
|
||||||
|
# Show some admin stuff
|
||||||
|
licences = []
|
||||||
|
try:
|
||||||
|
licences_file = open('/data/licence_key.txt', 'r')
|
||||||
|
licences = licences_file.readlines()
|
||||||
|
licences_file.close()
|
||||||
|
except FileNotFoundError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Create html page
|
||||||
|
html = "<h1>Admin</h1><br>"
|
||||||
|
html += "<h2>Licences</h2>"
|
||||||
|
html += "<p>Number of licences: " + str(len(licences)) + "</p>"
|
||||||
|
html += "<p>Licences:</p>"
|
||||||
|
html += "<ul>"
|
||||||
|
for licence in licences:
|
||||||
|
html += "<li>" + licence.strip('\n') + "</li>"
|
||||||
|
html += "</ul>"
|
||||||
|
html += "<h2>API</h2>"
|
||||||
|
html += "<p>API key: " + os.getenv('LICENCE_KEY') + "</p>"
|
||||||
|
html += "<p>Worker key: " + os.getenv('WORKER_KEY') + "</p>"
|
||||||
|
html += "<h2>Stripe</h2>"
|
||||||
|
# Check if stripe is enabled
|
||||||
|
if os.getenv('STRIPE_SECRET') == None:
|
||||||
|
html += "<p>Stripe is not enabled</p>"
|
||||||
|
else:
|
||||||
|
html += "<p>Stripe is enabled</p>"
|
||||||
|
|
||||||
|
html += "<br><br><h2>Workers</h2>"
|
||||||
|
workers = []
|
||||||
|
try:
|
||||||
|
workers_file = open('/data/workers.txt', 'r')
|
||||||
|
workers = workers_file.readlines()
|
||||||
|
workers_file.close()
|
||||||
|
except FileNotFoundError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
for worker in workers:
|
||||||
|
if not worker.__contains__(':'):
|
||||||
|
continue
|
||||||
|
|
||||||
|
html += "<p>Name: " + worker.split(':')[0] + " | Public IP " + worker.split(':')[2].strip('\n') + " | Private IP " + worker.split(':')[1]
|
||||||
|
# Check worker status
|
||||||
|
online=True
|
||||||
|
try:
|
||||||
|
resp=requests.get("http://"+worker.split(':')[1].strip('\n') + ":5000/status",timeout=2)
|
||||||
|
if (resp.status_code != 200):
|
||||||
|
html += " | Status: Offline"
|
||||||
|
else:
|
||||||
|
html += " | Status: Online | Sites: " + str(resp.json()['num_sites']) + " | Availability: " + str(resp.json()['availability'])
|
||||||
|
except:
|
||||||
|
html += " | Status: Offline"
|
||||||
|
|
||||||
|
html += "</p>"
|
||||||
|
|
||||||
|
|
||||||
|
html += "<h2>Sites</h2>"
|
||||||
|
sites = []
|
||||||
|
try:
|
||||||
|
sites_file = open('/data/sites.txt', 'r')
|
||||||
|
sites = sites_file.readlines()
|
||||||
|
sites_file.close()
|
||||||
|
except FileNotFoundError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
for site in sites:
|
||||||
|
if not site.__contains__(':'):
|
||||||
|
continue
|
||||||
|
domain = site.split(':')[0]
|
||||||
|
html += "<p>Domain: <a href='https://"+ domain + "'>" + domain + "</a> | Worker: " + site.split(':')[1].strip('\n') + " | <a href='/info?domain=" + domain + "'>Info</a></p>"
|
||||||
|
|
||||||
|
html += "<br><br>"
|
||||||
|
# Form to add worker
|
||||||
|
html += "<h2>Add worker</h2>"
|
||||||
|
html += "<form action='/new-worker' method='POST'>"
|
||||||
|
html += "<p>Name: <input type='text' name='name'></p>"
|
||||||
|
html += "<p>Public IP: <input type='text' name='ip'></p>"
|
||||||
|
html += "<p>Private IP: <input type='text' name='priv'></p>"
|
||||||
|
html += "<input type='submit' value='Add worker'>"
|
||||||
|
html += "</form>"
|
||||||
|
|
||||||
|
html += "<br><h2><a href='/licence'>Add Licence</a></h2><br>"
|
||||||
|
# Form to add site
|
||||||
|
html += "<h2>Add site</h2>"
|
||||||
|
html += "<form action='/add-site' method='POST'>"
|
||||||
|
html += "<p>Domain: <input type='text' name='domain'></p>"
|
||||||
|
html += "<input type='submit' value='Add site'>"
|
||||||
|
html += "</form>"
|
||||||
|
|
||||||
|
|
||||||
|
html += "<br><a href='/logout'>Logout</a></h2>"
|
||||||
|
|
||||||
|
|
||||||
|
return html
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/add-site', methods=['POST'])
|
||||||
|
def addsite():
|
||||||
|
# Check for licence key
|
||||||
|
if 'licence' not in request.form:
|
||||||
|
# Check cookie
|
||||||
|
login_key = request.cookies.get('login_key')
|
||||||
|
if login_key == None:
|
||||||
|
return redirect('/admin')
|
||||||
|
if login_key not in logins:
|
||||||
|
return redirect('/admin')
|
||||||
|
else:
|
||||||
|
# Use licence key
|
||||||
|
licence_key = request.form['licence']
|
||||||
|
# Check if licence key is valid
|
||||||
|
key_file = open('/data/licence_key.txt', 'r')
|
||||||
|
valid_key = False
|
||||||
|
for line in key_file.readlines():
|
||||||
|
if licence_key == line.strip('\n'):
|
||||||
|
valid_key = True
|
||||||
|
break
|
||||||
|
key_file.close()
|
||||||
|
if not valid_key:
|
||||||
|
return jsonify({'error': 'Invalid licence', 'success': 'false'})
|
||||||
|
|
||||||
|
# Delete licence key
|
||||||
|
key_file = open('/data/licence_key.txt', 'r')
|
||||||
|
lines = key_file.readlines()
|
||||||
|
key_file.close()
|
||||||
|
key_file = open('/data/licence_key.txt', 'w')
|
||||||
|
for line in lines:
|
||||||
|
if line.strip("\n") != licence_key:
|
||||||
|
key_file.write(line)
|
||||||
|
key_file.close()
|
||||||
|
|
||||||
|
# Get domain
|
||||||
|
domain = request.form['domain']
|
||||||
|
if domain == None:
|
||||||
|
return jsonify({'error': 'No domain sent', 'success': 'false'})
|
||||||
|
# Check if domain already exists
|
||||||
|
if site_exists(domain):
|
||||||
|
return jsonify({'error': 'Domain already exists', 'success': 'false'})
|
||||||
|
|
||||||
|
# Check if domain contains http:// or https://
|
||||||
|
if domain.startswith("http://") or domain.startswith("https://"):
|
||||||
|
return jsonify({'error': 'Domain should not contain http:// or https://', 'success': 'false'})
|
||||||
|
|
||||||
|
domain = domain.lower()
|
||||||
|
|
||||||
|
# Remove any trailing / or .
|
||||||
|
if domain.endswith('/'):
|
||||||
|
domain = domain.removesuffix('/')
|
||||||
|
if domain.endswith('.'):
|
||||||
|
domain = domain.removesuffix('.')
|
||||||
|
|
||||||
|
# Check if worker file exists
|
||||||
|
workers = None
|
||||||
|
try:
|
||||||
|
worker_file = open('/data/workers.txt', 'r')
|
||||||
|
workers = worker_file.readlines()
|
||||||
|
worker_file.close()
|
||||||
|
except FileNotFoundError:
|
||||||
|
return jsonify({'error': 'No workers available', 'success': 'false'})
|
||||||
|
|
||||||
|
# Get a worker that has available slots
|
||||||
|
worker = None
|
||||||
|
for line in workers:
|
||||||
|
if not line.__contains__(':'):
|
||||||
|
continue
|
||||||
|
|
||||||
|
ip = line.split(':')[1].strip('\n')
|
||||||
|
resp=requests.get("http://"+ip + ":5000/status",timeout=2)
|
||||||
|
if (resp.status_code == 200):
|
||||||
|
if resp.json()['availability'] == True:
|
||||||
|
worker = line
|
||||||
|
break
|
||||||
|
|
||||||
|
if worker == None:
|
||||||
|
return jsonify({'error': 'No workers available', 'success': 'false'})
|
||||||
|
|
||||||
|
|
||||||
|
# Add domain to file
|
||||||
|
sites_file = open('/data/sites.txt', 'a')
|
||||||
|
sites_file.write(domain + ':' + worker.split(':')[0] + '\n')
|
||||||
|
sites_file.close()
|
||||||
|
|
||||||
|
# Send worker request
|
||||||
|
requests.post("http://"+ worker.split(':')[1].strip('\n') + ":5000/new-site?domain=" + domain)
|
||||||
|
|
||||||
|
html = "<h1>Site creating...</h1><br>"
|
||||||
|
html += "<p>Domain: " + domain + "</p>"
|
||||||
|
html += "<p>Worker: " + worker.split(':')[0] + "</p>"
|
||||||
|
html += "<p>Worker IP: " + worker.split(':')[1].strip('\n') + "</p>"
|
||||||
|
html += "<p><a href='/info?domain=" + domain + "'>Check status</a></p>"
|
||||||
|
|
||||||
|
return html
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/licence')
|
||||||
|
def licence():
|
||||||
|
# Check cookie
|
||||||
|
login_key = request.cookies.get('login_key')
|
||||||
|
if login_key == None:
|
||||||
|
return redirect('/admin')
|
||||||
|
if login_key not in logins:
|
||||||
|
return redirect('/admin')
|
||||||
|
|
||||||
|
licence_key = os.urandom(16).hex()
|
||||||
|
|
||||||
|
# Add license key to file
|
||||||
|
key_file = open('/data/licence_key.txt', 'a')
|
||||||
|
key_file.write(licence_key + '\n')
|
||||||
|
key_file.close()
|
||||||
|
|
||||||
|
return "<h1>Licence key</h1><br><p>" + licence_key + "</p><br><a href='/admin'>Back</a>"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/new-worker', methods=['POST'])
|
||||||
|
def new_worker():
|
||||||
|
# Check cookie
|
||||||
|
login_key = request.cookies.get('login_key')
|
||||||
|
|
||||||
|
if login_key == None:
|
||||||
|
return redirect('/admin')
|
||||||
|
if login_key not in logins:
|
||||||
|
return redirect('/admin')
|
||||||
|
|
||||||
|
worker = request.form['name']
|
||||||
|
worker_IP = request.form['ip']
|
||||||
|
worker_PRIV = request.form['priv']
|
||||||
|
|
||||||
|
|
||||||
|
# Check worker file
|
||||||
|
try:
|
||||||
|
workers_file = open('/data/workers.txt', 'r')
|
||||||
|
except FileNotFoundError:
|
||||||
|
workers_file = open('/data/workers.txt', 'w')
|
||||||
|
workers_file.close()
|
||||||
|
workers_file = open('/data/workers.txt', 'r')
|
||||||
|
|
||||||
|
# Check if worker already exists
|
||||||
|
if worker in workers_file.read():
|
||||||
|
return jsonify({'error': 'Worker already exists', 'success': 'false'})
|
||||||
|
|
||||||
|
workers_file.close()
|
||||||
|
|
||||||
|
# Add worker to file
|
||||||
|
workers_file = open('/data/workers.txt', 'a')
|
||||||
|
workers_file.write(worker + ":" + worker_PRIV + ":"+ worker_IP + '\n')
|
||||||
|
workers_file.close()
|
||||||
|
|
||||||
|
return redirect('/admin')
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/logout')
|
||||||
|
def logout():
|
||||||
|
login_key = request.cookies.get('login_key')
|
||||||
|
if login_key == None:
|
||||||
|
return redirect('/admin')
|
||||||
|
if login_key not in logins:
|
||||||
|
return redirect('/admin')
|
||||||
|
|
||||||
|
logins.remove(login_key)
|
||||||
|
return redirect('/admin')
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/login', methods=['POST'])
|
||||||
|
def login():
|
||||||
|
# Handle login
|
||||||
|
print('Login attempt', flush=True)
|
||||||
|
# Check if form contains password
|
||||||
|
if 'password' not in request.form:
|
||||||
|
print('Login failed', flush=True)
|
||||||
|
return redirect('/failed-login')
|
||||||
|
|
||||||
|
password = request.form['password']
|
||||||
|
if os.getenv('ADMIN_KEY') == password:
|
||||||
|
print('Login success', flush=True)
|
||||||
|
# Generate login key
|
||||||
|
login_key = os.urandom(32).hex()
|
||||||
|
logins.append(login_key)
|
||||||
|
# Set cookie
|
||||||
|
resp = make_response(redirect('/admin'))
|
||||||
|
resp.set_cookie('login_key', login_key)
|
||||||
|
return resp
|
||||||
|
print('Login failed', flush=True)
|
||||||
|
return redirect('/failed-login')
|
||||||
|
|
||||||
|
@app.route('/failed-login')
|
||||||
|
def failed_login():
|
||||||
|
return "<h1>Failed login</h1><br><form action='/login' method='POST'><input type='password' name='password'><input type='submit' value='Login'></form>"
|
||||||
|
|
||||||
|
# Assets
|
||||||
|
@app.route('/assets/<path:path>')
|
||||||
|
def send_report(path):
|
||||||
|
return send_from_directory('templates/assets', path)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/terms')
|
||||||
|
def terms():
|
||||||
|
return render_template('terms.html')
|
||||||
|
|
||||||
|
# 404 route
|
||||||
|
@app.errorhandler(404)
|
||||||
|
def page_not_found(e):
|
||||||
|
return render_template('404.html'), 404
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Start the server
|
# Start the server
|
||||||
|
|||||||
32
master/templates/404.html
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html data-bs-theme="dark" lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
|
||||||
|
<title>HNSHosting WP</title>
|
||||||
|
<link rel="canonical" href="https://wp.hnshosting.au/404.html">
|
||||||
|
<meta property="og:url" content="https://wp.hnshosting.au/404.html">
|
||||||
|
<meta name="description" content="HNS Hosting Wordpress">
|
||||||
|
<link rel="icon" type="image/png" sizes="508x430" href="assets/img/favicon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="508x430" href="assets/img/favicon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="508x430" href="assets/img/favicon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="508x430" href="assets/img/favicon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="508x430" href="assets/img/favicon.png">
|
||||||
|
<link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css">
|
||||||
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Inter:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800&display=swap">
|
||||||
|
<link rel="stylesheet" href="assets/css/404.css">
|
||||||
|
<script async src="https://umami.woodburn.au/script.js" data-website-id="fc32daf3-6932-44ee-bbee-f853ce85d5f5"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<p>HTTP: <span>404</span></p>
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="text-start" style="display: inline-block;"><code><em>this_page</em>.<em>found</em> = false;</code><code><span>if</span> (<b>you_spelt_it_wrong</b>(<em>this_page</em>)) {<br><span class="tab-space"></span><b>try_again</b>();<br>} <span>else if</span> (!<em>this_page</em>.<b>content</b>) {<br><span class="tab-space"></span><b>you_spelt_it_wrong</b>('<i>You're lost! I'll send you back home</i>');<br><span class="tab-space"></span><span>window</span>.<b>location</b> = <em>home</em>;<br>}</code></div>
|
||||||
|
</div>
|
||||||
|
<script src="assets/bootstrap/js/bootstrap.min.js"></script>
|
||||||
|
<script src="assets/js/404.js"></script>
|
||||||
|
<script src="assets/js/bold-and-dark.js"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
6
master/templates/assets/bootstrap/css/bootstrap.min.css
vendored
Normal file
6
master/templates/assets/bootstrap/js/bootstrap.min.js
vendored
Normal file
79
master/templates/assets/css/404.css
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
* {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background: #282828;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-family: "Bevan", cursive;
|
||||||
|
font-size: 130px;
|
||||||
|
margin: 10vh 0 0;
|
||||||
|
text-align: center;
|
||||||
|
overflow-y: auto;
|
||||||
|
letter-spacing: 5px;
|
||||||
|
/*background-color: black;*/
|
||||||
|
color: black;
|
||||||
|
text-shadow: 2px 2px 3px rgba(255, 255, 255, 0.1);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-moz-background-clip: text;
|
||||||
|
background-clip: text;
|
||||||
|
}
|
||||||
|
|
||||||
|
p span {
|
||||||
|
font-size: 1.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
color: #bdbdbd;
|
||||||
|
text-align: left;
|
||||||
|
display: block;
|
||||||
|
overflow-y: auto;
|
||||||
|
font-size: 16px;
|
||||||
|
margin: 0 30px 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
code span {
|
||||||
|
color: #f0c674;
|
||||||
|
}
|
||||||
|
|
||||||
|
code i {
|
||||||
|
color: #b5bd68;
|
||||||
|
}
|
||||||
|
|
||||||
|
code em {
|
||||||
|
color: #b294bb;
|
||||||
|
font-style: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
code b {
|
||||||
|
color: #81a2be;
|
||||||
|
font-weight: 500;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #8abeb7;
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 20px;
|
||||||
|
text-decoration: underline;
|
||||||
|
overflow-y: auto;
|
||||||
|
margin-top: 10px;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 880px) {
|
||||||
|
p {
|
||||||
|
font-size: 14vw;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-space {
|
||||||
|
margin-left: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
BIN
master/templates/assets/img/brands/apple.png
Normal file
|
After Width: | Height: | Size: 9.1 KiB |
BIN
master/templates/assets/img/brands/facebook.png
Normal file
|
After Width: | Height: | Size: 7.8 KiB |
BIN
master/templates/assets/img/brands/google.png
Normal file
|
After Width: | Height: | Size: 8.3 KiB |
BIN
master/templates/assets/img/brands/microsoft.png
Normal file
|
After Width: | Height: | Size: 7.8 KiB |
BIN
master/templates/assets/img/brands/twitter.png
Normal file
|
After Width: | Height: | Size: 6.9 KiB |
BIN
master/templates/assets/img/favicon.png
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
master/templates/assets/img/products/1.jpg
Normal file
|
After Width: | Height: | Size: 43 KiB |
BIN
master/templates/assets/img/products/2.jpg
Normal file
|
After Width: | Height: | Size: 52 KiB |
BIN
master/templates/assets/img/products/3.jpg
Normal file
|
After Width: | Height: | Size: 57 KiB |
BIN
master/templates/assets/img/team/avatar2.jpg
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
master/templates/assets/img/team/avatar4.jpg
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
master/templates/assets/img/team/avatar5.jpg
Normal file
|
After Width: | Height: | Size: 57 KiB |
30
master/templates/assets/js/404.js
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
function callback(){
|
||||||
|
return function(){
|
||||||
|
alert("We're really sorry about that.");
|
||||||
|
window.location = '/';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var a = "world";
|
||||||
|
setTimeout(callback(), 7000);
|
||||||
|
|
||||||
|
function type(n, t) {
|
||||||
|
var str = document.getElementsByTagName("code")[n].innerHTML.toString();
|
||||||
|
var i = 0;
|
||||||
|
document.getElementsByTagName("code")[n].innerHTML = "";
|
||||||
|
|
||||||
|
setTimeout(function() {
|
||||||
|
var se = setInterval(function() {
|
||||||
|
i++;
|
||||||
|
document.getElementsByTagName("code")[n].innerHTML =
|
||||||
|
str.slice(0, i) + "|";
|
||||||
|
if (i == str.length) {
|
||||||
|
clearInterval(se);
|
||||||
|
document.getElementsByTagName("code")[n].innerHTML = str;
|
||||||
|
}
|
||||||
|
}, 10);
|
||||||
|
}, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
type(0, 0);
|
||||||
|
type(1, 600);
|
||||||
|
type(2, 1300);
|
||||||
61
master/templates/assets/js/bold-and-dark.js
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
(function() {
|
||||||
|
"use strict"; // Start of use strict
|
||||||
|
|
||||||
|
function initParallax() {
|
||||||
|
|
||||||
|
if (!('requestAnimationFrame' in window)) return;
|
||||||
|
if (/Mobile|Android/.test(navigator.userAgent)) return;
|
||||||
|
|
||||||
|
var parallaxItems = document.querySelectorAll('[data-bss-parallax]');
|
||||||
|
|
||||||
|
if (!parallaxItems.length) return;
|
||||||
|
|
||||||
|
var defaultSpeed = 0.5;
|
||||||
|
var visible = [];
|
||||||
|
var scheduled;
|
||||||
|
|
||||||
|
window.addEventListener('scroll', scroll);
|
||||||
|
window.addEventListener('resize', scroll);
|
||||||
|
|
||||||
|
scroll();
|
||||||
|
|
||||||
|
function scroll() {
|
||||||
|
|
||||||
|
visible.length = 0;
|
||||||
|
|
||||||
|
for (var i = 0; i < parallaxItems.length; i++) {
|
||||||
|
var rect = parallaxItems[i].getBoundingClientRect();
|
||||||
|
var speed = parseFloat(parallaxItems[i].getAttribute('data-bss-parallax-speed'), 10) || defaultSpeed;
|
||||||
|
|
||||||
|
if (rect.bottom > 0 && rect.top < window.innerHeight) {
|
||||||
|
visible.push({
|
||||||
|
speed: speed,
|
||||||
|
node: parallaxItems[i]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
cancelAnimationFrame(scheduled);
|
||||||
|
|
||||||
|
if (visible.length) {
|
||||||
|
scheduled = requestAnimationFrame(update);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function update() {
|
||||||
|
|
||||||
|
for (var i = 0; i < visible.length; i++) {
|
||||||
|
var node = visible[i].node;
|
||||||
|
var speed = visible[i].speed;
|
||||||
|
|
||||||
|
node.style.transform = 'translate3d(0, ' + (-window.scrollY * speed) + 'px, 0)';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
initParallax();
|
||||||
|
})(); // End of use strict
|
||||||
|
|
||||||
10
master/templates/assets/js/status_update.js
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
// Refresh page without status arg
|
||||||
|
|
||||||
|
// Wait 10 seconds
|
||||||
|
setTimeout(function() {
|
||||||
|
// Refresh page
|
||||||
|
// Get domain from param
|
||||||
|
var domain = urlParams.get('domain');
|
||||||
|
|
||||||
|
window.location = "https://hnshosting.au/success?domain=" + domain;
|
||||||
|
}, 10000);
|
||||||
174
master/templates/index.html
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html data-bs-theme="dark" lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
|
||||||
|
<title>Home - HNSHosting</title>
|
||||||
|
<link rel="canonical" href="https://wp.hnshosting.au/">
|
||||||
|
<meta property="og:url" content="https://wp.hnshosting.au/">
|
||||||
|
<meta name="description" content="HNS Hosting Wordpress">
|
||||||
|
<script type="application/ld+json">
|
||||||
|
{
|
||||||
|
"@context": "http://schema.org",
|
||||||
|
"@type": "WebSite",
|
||||||
|
"name": "HNSHosting",
|
||||||
|
"url": "https://wp.hnshosting.au"
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<link rel="icon" type="image/png" sizes="508x430" href="assets/img/favicon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="508x430" href="assets/img/favicon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="508x430" href="assets/img/favicon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="508x430" href="assets/img/favicon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="508x430" href="assets/img/favicon.png">
|
||||||
|
<link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css">
|
||||||
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Inter:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800&display=swap">
|
||||||
|
<script async src="https://umami.woodburn.au/script.js" data-website-id="fc32daf3-6932-44ee-bbee-f853ce85d5f5"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<nav class="navbar navbar-expand-md sticky-top py-3 navbar-dark" id="mainNav">
|
||||||
|
<div class="container"><a class="navbar-brand d-flex align-items-center" href="/"><span class="bs-icon-sm bs-icon-circle bs-icon-primary shadow d-flex justify-content-center align-items-center me-2 bs-icon" style="background: transparent;"><img src="assets/img/favicon.png" style="width: 100%;"></span><span>HNSHosting</span></a><button data-bs-toggle="collapse" class="navbar-toggler" data-bs-target="#navcol-1"><span class="visually-hidden">Toggle navigation</span><span class="navbar-toggler-icon"></span></button>
|
||||||
|
<div class="collapse navbar-collapse" id="navcol-1">
|
||||||
|
<ul class="navbar-nav mx-auto">
|
||||||
|
<li class="nav-item"><a class="nav-link active" href="/">Home</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link active" href="/#contact">Contact</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="/register">Register Site</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<header class="bg-dark">
|
||||||
|
<div class="container pt-4 pt-xl-5">
|
||||||
|
<div class="row pt-5">
|
||||||
|
<div class="col-md-8 col-xl-6 text-center text-md-start mx-auto">
|
||||||
|
<div class="text-center">
|
||||||
|
<h1 class="fw-bold">A simple and easy way to actually use your domain.</h1>
|
||||||
|
</div>
|
||||||
|
<p class="text-center" style="padding-bottom: 50px;padding-top: 25px;">Wordpress allows you to have an easily customizable website on your Handshake domain.</p>
|
||||||
|
<p class="text-center" style="font-size: 22px;">Currently hosting {{site_count}} wordpress sites!</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<section style="background: rgb(39,38,46);">
|
||||||
|
<div class="container bg-dark py-5" style="background: rgb(39, 38, 46);">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-8 col-xl-6 text-center mx-auto">
|
||||||
|
<p class="fw-bold text-success mb-2">Our Services</p>
|
||||||
|
<h3 class="fw-bold">What we do for you</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="py-5 p-lg-5">
|
||||||
|
<div class="row row-cols-1 row-cols-md-2 mx-auto" style="max-width: 900px;">
|
||||||
|
<div class="col mb-5">
|
||||||
|
<div class="card shadow-sm">
|
||||||
|
<div class="card-body px-4 py-5 px-md-5">
|
||||||
|
<div class="bs-icon-lg d-flex justify-content-center align-items-center mb-3 bs-icon" style="top: 1rem;right: 1rem;position: absolute;"><svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" viewBox="0 0 16 16" class="bi bi-shield-lock text-success">
|
||||||
|
<path d="M5.338 1.59a61.44 61.44 0 0 0-2.837.856.481.481 0 0 0-.328.39c-.554 4.157.726 7.19 2.253 9.188a10.725 10.725 0 0 0 2.287 2.233c.346.244.652.42.893.533.12.057.218.095.293.118a.55.55 0 0 0 .101.025.615.615 0 0 0 .1-.025c.076-.023.174-.061.294-.118.24-.113.547-.29.893-.533a10.726 10.726 0 0 0 2.287-2.233c1.527-1.997 2.807-5.031 2.253-9.188a.48.48 0 0 0-.328-.39c-.651-.213-1.75-.56-2.837-.855C9.552 1.29 8.531 1.067 8 1.067c-.53 0-1.552.223-2.662.524zM5.072.56C6.157.265 7.31 0 8 0s1.843.265 2.928.56c1.11.3 2.229.655 2.887.87a1.54 1.54 0 0 1 1.044 1.262c.596 4.477-.787 7.795-2.465 9.99a11.775 11.775 0 0 1-2.517 2.453 7.159 7.159 0 0 1-1.048.625c-.28.132-.581.24-.829.24s-.548-.108-.829-.24a7.158 7.158 0 0 1-1.048-.625 11.777 11.777 0 0 1-2.517-2.453C1.928 10.487.545 7.169 1.141 2.692A1.54 1.54 0 0 1 2.185 1.43 62.456 62.456 0 0 1 5.072.56"></path>
|
||||||
|
<path d="M9.5 6.5a1.5 1.5 0 0 1-1 1.415l.385 1.99a.5.5 0 0 1-.491.595h-.788a.5.5 0 0 1-.49-.595l.384-1.99a1.5 1.5 0 1 1 2-1.415z"></path>
|
||||||
|
</svg></div>
|
||||||
|
<h5 class="fw-bold card-title">Secured over SSL with DANE</h5>
|
||||||
|
<p class="text-muted card-text mb-4">Anyone with a resolver supporting DANE will be redirected to the HTTPS version on your site and will have an encrypted connection using DANE for verification.</p><a class="btn btn-primary shadow" role="button" target="_blank" href="https://en.wikipedia.org/wiki/DNS-based_Authentication_of_Named_Entities">Learn more</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col mb-5" style="margin-top: 150px;">
|
||||||
|
<div class="card shadow-sm">
|
||||||
|
<div class="card-body px-4 py-5 px-md-5">
|
||||||
|
<div class="bs-icon-lg d-flex justify-content-center align-items-center mb-3 bs-icon" style="top: 1rem;right: 1rem;position: absolute;"><svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" viewBox="0 0 16 16" class="bi bi-building-lock text-success">
|
||||||
|
<path d="M2 1a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v6.5a.5.5 0 0 1-1 0V1H3v14h3v-2.5a.5.5 0 0 1 .5-.5H8v4H3a1 1 0 0 1-1-1z"></path>
|
||||||
|
<path d="M4.5 2a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5zm2.5.5a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-1a.5.5 0 0 1-.5-.5zm3.5-.5a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5zM4 5.5a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-1a.5.5 0 0 1-.5-.5zM7.5 5a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5zm2.5.5a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-1a.5.5 0 0 1-.5-.5zM4.5 8a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5zm2.5.5a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-1a.5.5 0 0 1-.5-.5zM9 13a1 1 0 0 1 1-1v-1a2 2 0 1 1 4 0v1a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1h-4a1 1 0 0 1-1-1zm3-3a1 1 0 0 0-1 1v1h2v-1a1 1 0 0 0-1-1"></path>
|
||||||
|
</svg></div>
|
||||||
|
<h5 class="fw-bold card-title">Hosted with security in mind</h5>
|
||||||
|
<p class="text-muted card-text mb-4">The worker servers are fully secured so that the only access is HTTP for web traffic.<br>Any terminal access for maintenance is over a VPN tunnel to stop any unauthorized access. All SSH connections send a push notification to the admin's phone to alert him to any access.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col mb-4" style="margin-top: -150px;">
|
||||||
|
<div class="card shadow-sm">
|
||||||
|
<div class="card-body px-4 py-5 px-md-5">
|
||||||
|
<div class="bs-icon-lg d-flex justify-content-center align-items-center mb-3 bs-icon" style="top: 1rem;right: 1rem;position: absolute;"><svg xmlns="http://www.w3.org/2000/svg" height="1em" viewBox="0 0 24 24" width="1em" fill="currentColor" class="text-success">
|
||||||
|
<path d="M0 0h24v24H0z" fill="none"></path>
|
||||||
|
<path d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM14 13v4h-4v-4H7l5-5 5 5h-3z"></path>
|
||||||
|
</svg></div>
|
||||||
|
<h5 class="fw-bold card-title">Regular backups</h5>
|
||||||
|
<p class="text-muted card-text mb-4">The worker servers has weekly encrypted backups to an offsite location to allow recovery of any data if the server goes down.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<div class="container py-5">
|
||||||
|
<div class="mx-auto" style="max-width: 900px;">
|
||||||
|
<div class="row row-cols-1 row-cols-md-2 d-flex justify-content-center">
|
||||||
|
<div class="col mb-4">
|
||||||
|
<div class="card bg-primary-light">
|
||||||
|
<div class="card-body text-center px-4 py-5 px-md-5">
|
||||||
|
<p class="fw-bold text-primary card-text mb-2">Fully Managed</p>
|
||||||
|
<h5 class="fw-bold card-title mb-3">Control over plugins, users, access and everything with your site.</h5>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col mb-4">
|
||||||
|
<div class="card bg-secondary-light">
|
||||||
|
<div class="card-body text-center px-4 py-5 px-md-5">
|
||||||
|
<p class="fw-bold text-secondary card-text mb-2">Free Licences supported by OpenSystems</p>
|
||||||
|
<h5 class="fw-bold card-title mb-3">We offer a free tier with 1 GB storage capacity.<br>If you would like more please contact us to find an acceptable price for you.<br>Join our Discord for a free licence</h5>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section id="contact" class="py-5">
|
||||||
|
<div class="container">
|
||||||
|
<div class="row mb-5">
|
||||||
|
<div class="col-md-8 col-xl-6 text-center mx-auto">
|
||||||
|
<p class="fw-bold text-success mb-2">Contacts</p>
|
||||||
|
<h2 class="fw-bold">Contact Us</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row d-flex justify-content-center">
|
||||||
|
<div class="col-md-4 col-xl-4 d-flex justify-content-center justify-content-xl-start">
|
||||||
|
<div class="d-flex flex-wrap flex-md-column justify-content-md-start align-items-md-start h-100">
|
||||||
|
<div class="d-flex align-items-center p-3">
|
||||||
|
<div class="bs-icon-md bs-icon-circle bs-icon-primary shadow d-flex flex-shrink-0 justify-content-center align-items-center d-inline-block bs-icon bs-icon-md"><svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" viewBox="0 0 16 16" class="bi bi-discord">
|
||||||
|
<path d="M13.545 2.907a13.227 13.227 0 0 0-3.257-1.011.05.05 0 0 0-.052.025c-.141.25-.297.577-.406.833a12.19 12.19 0 0 0-3.658 0 8.258 8.258 0 0 0-.412-.833.051.051 0 0 0-.052-.025c-1.125.194-2.22.534-3.257 1.011a.041.041 0 0 0-.021.018C.356 6.024-.213 9.047.066 12.032c.001.014.01.028.021.037a13.276 13.276 0 0 0 3.995 2.02.05.05 0 0 0 .056-.019c.308-.42.582-.863.818-1.329a.05.05 0 0 0-.01-.059.051.051 0 0 0-.018-.011 8.875 8.875 0 0 1-1.248-.595.05.05 0 0 1-.02-.066.051.051 0 0 1 .015-.019c.084-.063.168-.129.248-.195a.05.05 0 0 1 .051-.007c2.619 1.196 5.454 1.196 8.041 0a.052.052 0 0 1 .053.007c.08.066.164.132.248.195a.051.051 0 0 1-.004.085 8.254 8.254 0 0 1-1.249.594.05.05 0 0 0-.03.03.052.052 0 0 0 .003.041c.24.465.515.909.817 1.329a.05.05 0 0 0 .056.019 13.235 13.235 0 0 0 4.001-2.02.049.049 0 0 0 .021-.037c.334-3.451-.559-6.449-2.366-9.106a.034.034 0 0 0-.02-.019Zm-8.198 7.307c-.789 0-1.438-.724-1.438-1.612 0-.889.637-1.613 1.438-1.613.807 0 1.45.73 1.438 1.613 0 .888-.637 1.612-1.438 1.612m5.316 0c-.788 0-1.438-.724-1.438-1.612 0-.889.637-1.613 1.438-1.613.807 0 1.451.73 1.438 1.613 0 .888-.631 1.612-1.438 1.612"></path>
|
||||||
|
</svg></div>
|
||||||
|
<div class="px-2">
|
||||||
|
<h6 class="fw-bold mb-0">Discord</h6>
|
||||||
|
<p class="text-muted mb-0"><a href="https://l.woodburn.au/discord" target="_blank">Join our server</a></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex align-items-center p-3">
|
||||||
|
<div class="bs-icon-md bs-icon-circle bs-icon-primary shadow d-flex flex-shrink-0 justify-content-center align-items-center d-inline-block bs-icon bs-icon-md"><svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" viewBox="0 0 16 16" class="bi bi-envelope">
|
||||||
|
<path d="M0 4a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2zm2-1a1 1 0 0 0-1 1v.217l7 4.2 7-4.2V4a1 1 0 0 0-1-1zm13 2.383-4.708 2.825L15 11.105zm-.034 6.876-5.64-3.471L8 9.583l-1.326-.795-5.64 3.47A1 1 0 0 0 2 13h12a1 1 0 0 0 .966-.741M1 11.105l4.708-2.897L1 5.383z"></path>
|
||||||
|
</svg></div>
|
||||||
|
<div class="px-2">
|
||||||
|
<h6 class="fw-bold mb-0">Email</h6>
|
||||||
|
<p class="text-muted mb-0"><a href="mailto:support@hnshosting.au">support@hnshosting.au</a></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<footer class="bg-dark">
|
||||||
|
<div class="container py-4 py-lg-5">
|
||||||
|
<hr>
|
||||||
|
<div class="text-muted d-flex justify-content-between align-items-center pt-3">
|
||||||
|
<p class="mb-0">Copyright © 2023 HNSHosting</p><a href="/terms">Terms & Privacy</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
<script src="assets/bootstrap/js/bootstrap.min.js"></script>
|
||||||
|
<script src="assets/js/bold-and-dark.js"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
71
master/templates/register.html
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html data-bs-theme="dark" lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
|
||||||
|
<title>Sign up - HNSHosting</title>
|
||||||
|
<link rel="canonical" href="https://wp.hnshosting.au/register.html">
|
||||||
|
<meta property="og:url" content="https://wp.hnshosting.au/register.html">
|
||||||
|
<meta name="description" content="HNS Hosting Wordpress">
|
||||||
|
<link rel="icon" type="image/png" sizes="508x430" href="assets/img/favicon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="508x430" href="assets/img/favicon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="508x430" href="assets/img/favicon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="508x430" href="assets/img/favicon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="508x430" href="assets/img/favicon.png">
|
||||||
|
<link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css">
|
||||||
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Inter:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800&display=swap">
|
||||||
|
<script async src="https://umami.woodburn.au/script.js" data-website-id="fc32daf3-6932-44ee-bbee-f853ce85d5f5"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<nav class="navbar navbar-expand-md sticky-top py-3 navbar-dark" id="mainNav">
|
||||||
|
<div class="container"><a class="navbar-brand d-flex align-items-center" href="/"><span class="bs-icon-sm bs-icon-circle bs-icon-primary shadow d-flex justify-content-center align-items-center me-2 bs-icon" style="background: transparent;"><img src="assets/img/favicon.png" style="width: 100%;"></span><span>HNSHosting</span></a><button data-bs-toggle="collapse" class="navbar-toggler" data-bs-target="#navcol-1"><span class="visually-hidden">Toggle navigation</span><span class="navbar-toggler-icon"></span></button>
|
||||||
|
<div class="collapse navbar-collapse" id="navcol-1">
|
||||||
|
<ul class="navbar-nav mx-auto">
|
||||||
|
<li class="nav-item"><a class="nav-link" href="/">Home</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="/#contact">Contact</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="/register">Register Site</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<section class="py-5">
|
||||||
|
<div class="container py-5">
|
||||||
|
<div class="row mb-4 mb-lg-5">
|
||||||
|
<div class="col-md-8 col-xl-6 text-center mx-auto">
|
||||||
|
<p class="fw-bold text-success mb-2">Register site</p>
|
||||||
|
<h2 class="fw-bold">Get started with your Hosting here.</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row d-flex justify-content-center">
|
||||||
|
<div class="col-md-6 col-xl-4">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body text-center d-flex flex-column align-items-center">
|
||||||
|
<form method="post" action="/register">
|
||||||
|
<div class="mb-3"><input type="text" name="domain" placeholder="Domain"></div>
|
||||||
|
<div class="mb-3"><input type="text" placeholder="Licence Key" name="licence"></div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<p style="color: rgb(255,0,0);">{{ERROR_MESSAGE}}</p><button class="btn btn-primary shadow d-block w-100" type="submit">Create site</button>
|
||||||
|
</div>
|
||||||
|
<p class="text-muted">Don't have a licence?<br><a href="{{buy_licence_link}}" target="_blank">Click here to buy one</a><br>Or thanks to the OpenSystems grant<br><a href="https://l.woodburn.au/discord" target="_blank">Register a free site here</a></p>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<footer class="bg-dark">
|
||||||
|
<div class="container py-4 py-lg-5">
|
||||||
|
<hr>
|
||||||
|
<div class="text-muted d-flex justify-content-between align-items-center pt-3">
|
||||||
|
<p class="mb-0">Copyright © 2023 HNSHosting</p><a href="/terms">Terms & Privacy</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
<script src="assets/bootstrap/js/bootstrap.min.js"></script>
|
||||||
|
<script src="assets/js/bold-and-dark.js"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
57
master/templates/success.html
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html data-bs-theme="dark" lang="en" style="height: 100%;">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
|
||||||
|
<title>Home - HNSHosting</title>
|
||||||
|
<link rel="canonical" href="https://wp.hnshosting.au/success.html">
|
||||||
|
<meta property="og:url" content="https://wp.hnshosting.au/success.html">
|
||||||
|
<meta name="description" content="HNS Hosting Wordpress">
|
||||||
|
<link rel="icon" type="image/png" sizes="508x430" href="assets/img/favicon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="508x430" href="assets/img/favicon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="508x430" href="assets/img/favicon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="508x430" href="assets/img/favicon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="508x430" href="assets/img/favicon.png">
|
||||||
|
<link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css">
|
||||||
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Inter:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800&display=swap">
|
||||||
|
<script async src="https://umami.woodburn.au/script.js" data-website-id="fc32daf3-6932-44ee-bbee-f853ce85d5f5"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body style="height: 100%;">
|
||||||
|
<nav class="navbar navbar-expand-md sticky-top py-3 navbar-dark" id="mainNav">
|
||||||
|
<div class="container"><a class="navbar-brand d-flex align-items-center" href="/"><span class="bs-icon-sm bs-icon-circle bs-icon-primary shadow d-flex justify-content-center align-items-center me-2 bs-icon" style="background: transparent;"><img src="assets/img/favicon.png" style="width: 100%;"></span><span>HNSHosting</span></a><button data-bs-toggle="collapse" class="navbar-toggler" data-bs-target="#navcol-1"><span class="visually-hidden">Toggle navigation</span><span class="navbar-toggler-icon"></span></button>
|
||||||
|
<div class="collapse navbar-collapse" id="navcol-1">
|
||||||
|
<ul class="navbar-nav mx-auto">
|
||||||
|
<li class="nav-item"><a class="nav-link" href="/">Home</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="/#contact">Contact</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="/register">Register Site</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<header class="bg-dark" style="height: 75%;">
|
||||||
|
<div class="container pt-4 pt-xl-5">
|
||||||
|
<div class="row pt-5" style="height: 100%;">
|
||||||
|
<div class="col-md-8 col-xl-6 text-center text-md-start mx-auto">
|
||||||
|
<div class="text-center">
|
||||||
|
<p class="fw-bold text-success mb-2">Success</p>
|
||||||
|
<h1 class="fw-bold">{{title | safe}}</h1></div><p class="text-center">{{message | safe}}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<footer class="bg-dark">
|
||||||
|
<div class="container py-4 py-lg-5">
|
||||||
|
<hr>
|
||||||
|
<div class="text-muted d-flex justify-content-between align-items-center pt-3">
|
||||||
|
<p class="mb-0">Copyright © 2023 HNSHosting</p><a href="/terms">Terms & Privacy</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
<script src="assets/bootstrap/js/bootstrap.min.js"></script>
|
||||||
|
<script src="assets/js/bold-and-dark.js"></script>
|
||||||
|
<script src="assets/js/status_update.js"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
59
master/templates/terms.html
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html data-bs-theme="dark" lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
|
||||||
|
<title>Terms - HNSHosting</title>
|
||||||
|
<link rel="canonical" href="https://wp.hnshosting.au/terms.html">
|
||||||
|
<meta property="og:url" content="https://wp.hnshosting.au/terms.html">
|
||||||
|
<meta name="description" content="HNS Hosting Wordpress">
|
||||||
|
<link rel="icon" type="image/png" sizes="508x430" href="assets/img/favicon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="508x430" href="assets/img/favicon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="508x430" href="assets/img/favicon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="508x430" href="assets/img/favicon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="508x430" href="assets/img/favicon.png">
|
||||||
|
<link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css">
|
||||||
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Inter:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800&display=swap">
|
||||||
|
<script async src="https://umami.woodburn.au/script.js" data-website-id="fc32daf3-6932-44ee-bbee-f853ce85d5f5"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<nav class="navbar navbar-expand-md sticky-top py-3 navbar-dark" id="mainNav">
|
||||||
|
<div class="container"><a class="navbar-brand d-flex align-items-center" href="/"><span class="bs-icon-sm bs-icon-circle bs-icon-primary shadow d-flex justify-content-center align-items-center me-2 bs-icon" style="background: transparent;"><img src="assets/img/favicon.png" style="width: 100%;"></span><span>HNSHosting</span></a><button data-bs-toggle="collapse" class="navbar-toggler" data-bs-target="#navcol-1"><span class="visually-hidden">Toggle navigation</span><span class="navbar-toggler-icon"></span></button>
|
||||||
|
<div class="collapse navbar-collapse" id="navcol-1">
|
||||||
|
<ul class="navbar-nav mx-auto">
|
||||||
|
<li class="nav-item"><a class="nav-link" href="/">Home</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="/#contact">Contact</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="/register">Register Site</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<section class="py-5">
|
||||||
|
<div class="container py-5">
|
||||||
|
<div class="row mb-4 mb-lg-5">
|
||||||
|
<div class="col-md-8 col-xl-6 text-center mx-auto">
|
||||||
|
<p class="fw-bold text-success mb-2">Terms of Service</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row d-flex justify-content-center">
|
||||||
|
<div class="col">
|
||||||
|
<p>Terms of Service for HNSHosting Website Hosting<br><br>Last Updated: 17/11/23<br><br>Welcome to HNSHosting! Please carefully read the following terms before using our hosting services.<br><br>By using our website hosting services, you agree to comply with and be bound by the following terms and conditions. If you do not agree to these terms, please do not use our services.<br><br><strong>1. Acceptance of Terms:</strong><br>By accessing or using our website hosting services, you agree to these Terms of Service and all applicable laws and regulations.<br><br><strong>2. Hosting Services:</strong><br>HNSHosting provides hosting services for websites, and related content.<br><br><strong>3. Account Registration:</strong><br>To use our hosting services, you must create a Wordpress administrator account. You are responsible for maintaining the security of your account and any actions taken under your account credentials.<br><br><strong>4. Payment and Billing:</strong><br>Payment for hosting services is required in accordance with the pricing and billing terms specified on our website. Failure to pay may result in the suspension or termination of your hosting services.<br><br><strong>5. Content and Usage:</strong><br>You are solely responsible for the content hosted on your website. You agree not to host any content that violates applicable laws or infringes on the rights of others. This includes anything usually classified as <em>NSFW</em>. HNSHosting reserves the right to suspend or terminate services for any user found in violation of this provision.<br><br><strong>6. Data Security:</strong><br>We implement reasonable measures to protect the security of your data, but we cannot guarantee its absolute security. You should backup any critical data using your own backup solution.<br><br><strong>7. Uptime and Downtime:</strong><br>HNSHosting strives to provide high uptime for its hosting services. However, downtime may occur for maintenance or other reasons. We will make reasonable efforts to notify you in advance of scheduled maintenance.<br><br><strong>8. Support:</strong><br>We offer customer support for technical issues related to our hosting services. Support availability and response times may vary. We can not guarantee support for issues unrelated to our hosting services.<br><br><strong>9. Termination:</strong><br>HNSHosting reserves the right to terminate or suspend your account at any time for violation of these terms or for any other reason. You may also terminate your account by contacting us.<br><br><strong>10. Changes to Terms:</strong><br>HNSHosting reserves the right to modify these Terms of Service at any time. Any changes will be effective immediately upon posting on our website. It is your responsibility to review these terms regularly.<br><br><br>By using our hosting services, you agree to these terms. If you have any questions or concerns, please contact us.<br>Thank you for choosing HNSHosting Services!<br><br><br><br><br><br></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<footer class="bg-dark">
|
||||||
|
<div class="container py-4 py-lg-5">
|
||||||
|
<hr>
|
||||||
|
<div class="text-muted d-flex justify-content-between align-items-center pt-3">
|
||||||
|
<p class="mb-0">Copyright © 2023 HNSHosting</p><a href="/terms">Terms & Privacy</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
<script src="assets/bootstrap/js/bootstrap.min.js"></script>
|
||||||
|
<script src="assets/js/bold-and-dark.js"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
@@ -2,23 +2,44 @@
|
|||||||
# Initial install for all prerequisites for the project.
|
# Initial install for all prerequisites for the project.
|
||||||
# This makes it quicker to get each site up and running.
|
# This makes it quicker to get each site up and running.
|
||||||
|
|
||||||
# Update the system
|
# Stop kernel prompts
|
||||||
sudo apt update && sudo apt upgrade -y
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
export NEEDRESTART_MODE=a
|
||||||
|
echo "Dpkg::Options { \"--force-confdef\"; \"--force-confold\"; };" | sudo tee /etc/apt/apt.conf.d/local
|
||||||
|
|
||||||
|
KERNEL_VERSION=$(uname -r)
|
||||||
|
sudo apt-mark hold linux-image-generic linux-headers-generic linux-generic linux-image-$KERNEL_VERSION linux-headers-$KERNEL_VERSION
|
||||||
|
|
||||||
# Install Docker
|
# Install Docker
|
||||||
sudo apt install apt-transport-https ca-certificates curl software-properties-common -y
|
sudo apt update
|
||||||
|
sudo apt install apt-transport-https ca-certificates curl software-properties-common python3-pip nginx -y
|
||||||
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
|
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
|
||||||
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
||||||
sudo apt update
|
sudo apt update
|
||||||
apt-cache policy docker-ce
|
apt-cache policy docker-ce
|
||||||
sudo apt install docker-ce -y
|
sudo apt install docker-ce docker-compose -y
|
||||||
sudo apt install docker-compose -y
|
|
||||||
|
|
||||||
# Install NGINX
|
|
||||||
sudo apt install nginx -y
|
|
||||||
|
|
||||||
# Install python prerequisites
|
# Install python prerequisites
|
||||||
sudo apt install python3-pip -y
|
|
||||||
python3 -m pip install -r requirements.txt
|
python3 -m pip install -r requirements.txt
|
||||||
cp .env.example .env
|
cp .env.example .env
|
||||||
chmod +x wp.sh tlsa.sh
|
chmod +x wp.sh tlsa.sh
|
||||||
|
|
||||||
|
# Add proxy to docker
|
||||||
|
mkdir ~/.docker
|
||||||
|
echo """{
|
||||||
|
\"proxies\": {
|
||||||
|
\"default\": {
|
||||||
|
\"httpProxy\": \"http://proxy.hnsproxy.au:80\",
|
||||||
|
\"httpsProxy\": \"https://proxy.hnsproxy.au:443\",
|
||||||
|
\"noProxy\": \"localhost\"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}""" > ~/.docker/config.json
|
||||||
|
|
||||||
|
# Restart docker
|
||||||
|
sudo systemctl restart docker
|
||||||
|
|
||||||
|
# Pull docker images to save time later
|
||||||
|
docker pull mysql:5.7 &
|
||||||
|
docker pull wordpress:latest &
|
||||||
|
wait
|
||||||
@@ -44,8 +44,8 @@ def tlsa():
|
|||||||
tlsa_file = open('wordpress-'+domain+'/tlsa.txt', 'r')
|
tlsa_file = open('wordpress-'+domain+'/tlsa.txt', 'r')
|
||||||
tlsa = tlsa_file.readlines()
|
tlsa = tlsa_file.readlines()
|
||||||
tlsa_file.close()
|
tlsa_file.close()
|
||||||
except FileNotFoundError:
|
except FileNotFoundError as e:
|
||||||
return jsonify({'error': 'TLSA record not found', 'success': 'false'})
|
return jsonify({'error': 'TLSA record not found', 'success': 'false', 'ex': str(e)})
|
||||||
|
|
||||||
# Remove newlines
|
# Remove newlines
|
||||||
tlsa = tlsa[0].strip('\n')
|
tlsa = tlsa[0].strip('\n')
|
||||||
@@ -67,16 +67,11 @@ def ping():
|
|||||||
return 'pong'
|
return 'pong'
|
||||||
|
|
||||||
def get_sites_count():
|
def get_sites_count():
|
||||||
# If file doesn't exist, create it
|
# Get number of files in nginx/sites
|
||||||
try:
|
dir = os.listdir('/etc/nginx/sites-available')
|
||||||
sites_file = open('sites.txt', 'r')
|
num_Sites = len(dir) - 1
|
||||||
except FileNotFoundError:
|
|
||||||
sites_file = open('sites.txt', 'w')
|
|
||||||
sites_file.close()
|
|
||||||
sites_file = open('sites.txt', 'r')
|
|
||||||
print(sites_file.readlines())
|
|
||||||
# Return number of lines in file
|
# Return number of lines in file
|
||||||
return len(sites_file.readlines())
|
return num_Sites
|
||||||
|
|
||||||
def site_exists(domain):
|
def site_exists(domain):
|
||||||
# If file doesn't exist, create it
|
# If file doesn't exist, create it
|
||||||
|
|||||||
14
worker/wp.sh
@@ -43,6 +43,8 @@ services:
|
|||||||
MYSQL_DATABASE: WordPressDatabase
|
MYSQL_DATABASE: WordPressDatabase
|
||||||
MYSQL_USER: WordPressUser
|
MYSQL_USER: WordPressUser
|
||||||
MYSQL_PASSWORD: $MYSQL_PASSWORD
|
MYSQL_PASSWORD: $MYSQL_PASSWORD
|
||||||
|
volumes:
|
||||||
|
- mysql:/var/lib/mysql
|
||||||
wordpress:
|
wordpress:
|
||||||
depends_on:
|
depends_on:
|
||||||
- ${DOMAIN}db
|
- ${DOMAIN}db
|
||||||
@@ -56,9 +58,11 @@ services:
|
|||||||
WORDPRESS_DB_PASSWORD: $MYSQL_PASSWORD
|
WORDPRESS_DB_PASSWORD: $MYSQL_PASSWORD
|
||||||
WORDPRESS_DB_NAME: WordPressDatabase
|
WORDPRESS_DB_NAME: WordPressDatabase
|
||||||
volumes:
|
volumes:
|
||||||
[\"./:/var/www/html\"]
|
- data:/var/www/html
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
mysql: {}
|
mysql:
|
||||||
|
data:
|
||||||
""" > docker-compose.yml
|
""" > docker-compose.yml
|
||||||
|
|
||||||
# Start the containers
|
# Start the containers
|
||||||
@@ -85,6 +89,12 @@ printf "server {
|
|||||||
sub_filter_once on;
|
sub_filter_once on;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
location = /.well-known/wallets/HNS {
|
||||||
|
proxy_pass $URL;
|
||||||
|
proxy_set_header Host \$http_host;
|
||||||
|
rewrite ^(.*)$ \$1/ break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
listen 443 ssl;
|
listen 443 ssl;
|
||||||
ssl_certificate /etc/ssl/$DOMAIN.crt;
|
ssl_certificate /etc/ssl/$DOMAIN.crt;
|
||||||
|
|||||||