diff --git a/README.md b/README.md index 87b912e..9bd4571 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ This project is released under the CC0-1.0 license. The code and content are in # Install and self-host Have a weird obsession? Want a pre-built site you can use for free? Host aidxnFUN! As the code is available under the CC0-1.0 license, which means you should feel free and encouraged to change content, design, whatever! -During this process, `node` (20.08.0), `npm`, and `docker` will be installed on your computer. +During this process, `node` (20.08.0), `npm`, and `netcat` will be installed on your computer. Please note the /status endpoint will be broken with the original servers as CORS is blocked on sites not requesting from my personal domain. @@ -23,26 +23,17 @@ Please note the /status endpoint will be broken with the original servers as COR ```bash ./manage setup ``` -3. Edit example files - ```bash - nano docker-compose.yml # Edit Docker Compose (database server) - nano config.json # Edit config.json (database config) - ``` - - When editing config.json, use server details from docker-compose.yml so they are linked together. Ensure you double-check the IP or hostname of the Docker container, and link that with the .env file. This is crucial, or your database will not be connected. - - Database features are only for analytics, at this time. -4. Start the server +3. Start the server ```bash ./manage up ``` A server will now start on port :5566, and be accessible from your web browser at http://localhost:5566/. I highly suggest creating a NGINX reverse proxy for this, especially if you plan to point this to a domain. ## Windows -Windows is currently not supported by aidxnFUN yet. I suggest you use WSL, and follow the Linux instructions, or purchase a server. +Windows is currently not supported by aidxnFUN yet. I suggest you use WSL, and follow the Ubuntu instructions, or purchase a VPS. # How it works -This website uses Node.js, Express.js for a server, EJS for templating, and Tailwind CSS for the frontend CSS. It additionally uses Docker (w/ MariaDB and optionally PhpMyAdmin) for managing the database, which is used in the analytics system. +This website uses Node.js, Express.js for a server, EJS for templating, and Tailwind CSS for the frontend CSS. The `manage` script uses all of those tools to manage the server for you executes the repetitive tasks for you automatically. The views contain both regular page shards (full-ish pages) and generic shards (fragments of pages, widgets, etc.). I define a "shard" as an EJS template, which are pieced together into a pretty little website. The shards hold individual elements like music widgets, while a regular page shard is the page that contains the music widget, which the end user sees. This is helpful for understanding the code. @@ -50,56 +41,6 @@ Thus far, shards are included for a music widget, the header, and the footer of Music (as featured on the home page) is fetched from an API (hosted on https://biancarosa.com.br), which I am in the process of setting up for myself. It works with a LastFM account (I linked this to my Spotify) and can track your live listening with amazing accuracy. The repo can be found at [biancarosa/lastfm-last-played](https://github.com/biancarosa/lastfm-last-played). -# Sample docker-compose.yml - (suggested) -```dockerfile -services: - aidxnfun-db: - image: mariadb:latest - networks: - aidxnfun-n: - ipv4_address: 10.5.0.5 - environment: - MYSQL_ROOT_PASSWORD: iloveaidxnfun123 - MYSQL_DATABASE: aidxnfun - MYSQL_USER: aidxnfun - MYSQL_PASSWORD: iloveaidxnfun - volumes: - - ./db_storage:/var/lib/mysql - restart: unless-stopped - phpmyadmin: - image: phpmyadmin - restart: always - networks: - aidxnfun-n: - ipv4_address: 10.5.0.6 - ports: - - 80:80 - environment: - - PMA_ARBITRARY=1 - -networks: - aidxnfun-n: - external: true - ipam: - config: - - subnet: 10.5.0.0/16 - gateway: 10.5.0.1 -``` - -This can be used in conjunction with this example config.json file: - -```json -{ - "DB_HOST": "10.5.0.05", - "DB_PORT": 3306, - "DB_USER": "root", - "DB_PASSWORD": "iloveaidxnfun123", - "DB_NAME": "aidxnfun" -} -``` - -This config will create a MariaDB instance, with a pre-created database, as long well as supplied user credentials. A PhpMyAdmin instance will additionally be spun up for easy management and inspection of the database. You may plug in `10.5.0.5` as the host on [your ip]:80 in your web browser (on the computer running Docker). - # Using the `manage` script You may have noticed you have a `manage` file after cloning. `manage` is a command-line tool to manage the server. It can automatically start, stop, and restart your instance. @@ -121,20 +62,12 @@ After doing that, you are now ready to use the script. + `./manage status, -s, --status` - Checks if the server is running. + `./manage help, -h, --help` - Shows the help message. -## `manage` options -+ `--db-alive` - Do not restart Docker services (database). - # Troubleshooting -I highly suggest you take a peek at the `node.log` file's contents. It's in the same directory as the `manage` script. This shows the web server's full startup, which can help you find out if the database isn't configured right, or something else is going wrong. - -If the database just started, give it 30 or so seconds and issue `./manage restart --db-alive` to restart the server without touching the database. It's common to get into a Docker-and-Node restart loop (which are not in sync) which I'm fixing. +I highly suggest you take a peek at the `node.log` file's contents. It's in the same directory as the `manage` script. This file contains the NodeJS server logs, which can be very helpful for debugging and/or troubleshooting. # To-Do - [ ] Implement PGP message verification -- [ ] Improve `manage` handling of waiting for database to start (switch from predefined number of seconds) - [X] Add menu link to tilde website -- [X] Add database support -- [X] Add view counter - [X] Update projects page to latest information # License diff --git a/app.js b/app.js index b228dec..ad748fb 100644 --- a/app.js +++ b/app.js @@ -1,97 +1,13 @@ const express = require('express'); const path = require('path'); -const mysql = require('mysql2'); const fs = require('fs'); -const config = JSON.parse(fs.readFileSync('./config.json', 'utf8')); - const app = express(); app.set('view engine', 'ejs'); app.set('views', path.join(__dirname, 'views')); app.use(express.static(path.join(__dirname, 'public'))); app.use(express.json()); -const db = mysql.createConnection({ - host: config.DB_HOST, - port: config.DB_PORT, - user: config.DB_USER, - password: config.DB_PASSWORD, - database: config.DB_NAME, -}); - -const dbInit = () => { - if (!fs.existsSync('.db_init')) { - console.log('.db_init not found, initializing db...'); - - const createVT = ` - CREATE TABLE page_views ( - page VARCHAR(255) PRIMARY KEY, - views INT DEFAULT 0 - )`; - - db.query(createVT, (error) => { - if (error) throw error; - console.log('Views table created successfully.'); - insertPages(); - fs.writeFileSync('.db_init', 'complete'); - }); - - db.query(`SHOW TABLES LIKE 'page_views'`, (err, results) => { - if (err) throw err; - - if (results.length === 0) { - const createVT = ` - CREATE TABLE page_views ( - page VARCHAR(255) PRIMARY KEY, - views INT DEFAULT 0 - )`; - - db.query(createVT, (error) => { - if (error) throw error; - console.log('Views table created successfully.'); - insertPages(); - fs.writeFileSync('.db_init', 'complete'); - }); - } else { - console.log('Views table already exists, skipping.'); - insertPages(); - } - }); - } else { - console.log('.db_init file found, skipping database initialization.'); - } -}; - -const insertPages = () => { - const pages = ['/', '/about', '/contact', '/verify', '/status', '/design', '/projects', '/cloud']; - pages.forEach(page => { - const sql = `INSERT IGNORE INTO page_views (page, views) VALUES (?, 0)`; - db.query(sql, [page], (error) => { - if (error) throw error; - }); - }); -}; - -db.connect((err) => { - if (err) throw err; - console.log('Connected to database.'); - dbInit(); -}); - -app.post('/api/log-view', (req, res) => { - const { page } = req.body; - const sql = `UPDATE page_views SET views = views + 1 WHERE page = ?`; - db.query(sql, [page], (error) => { - if (error) return res.status(500).json({ error }); - - const selectSql = `SELECT views FROM page_views WHERE page = ?`; - db.query(selectSql, [page], (error, results) => { - if (error) return res.status(500).json({ error }); - res.json({ views: results[0].views }); - }); - }); -}); - const routes = ['/', '/about', '/contact', '/verify', '/status', '/design', '/projects', '/cloud']; routes.forEach(route => { app.get(route, (req, res) => { diff --git a/config.json.example b/config.json.example deleted file mode 100644 index ecb0dbd..0000000 --- a/config.json.example +++ /dev/null @@ -1,7 +0,0 @@ -{ - "DB_HOST": "10.5.0.5", - "DB_PORT": 3306, - "DB_USER": "root", - "DB_PASSWORD": "iloveaidxnfun123", - "DB_NAME": "aidxnfun" -} \ No newline at end of file diff --git a/docker-compose.yml.example b/docker-compose.yml.example deleted file mode 100644 index e7c3497..0000000 --- a/docker-compose.yml.example +++ /dev/null @@ -1,11 +0,0 @@ -services: - db: - image: mariadb:latest - environment: - MYSQL_ROOT_PASSWORD: iloveaidxnfun123 - MYSQL_DATABASE: aidxnfun - MYSQL_USER: aidxnfun - MYSQL_PASSWORD: iloveaidxnfun - volumes: - - /docker/db/mysql:/var/lib/mysql - restart: unless-stopped \ No newline at end of file diff --git a/manage b/manage index ee0fa1c..553f3ee 100755 --- a/manage +++ b/manage @@ -1,6 +1,6 @@ #!/bin/bash -SC_VERSION=1.1.0 +SC_VERSION=1.2.0 SC_CODENAME="bionic" PORT=5566 SETUP_FILE=".setup_complete" @@ -11,43 +11,7 @@ COLOR_YELLOW="\033[1;33m" COLOR_BLUE="\033[1;34m" COLOR_CYAN="\033[1;36m" -check_db() { - nc -z "$DB_HOST" "$DB_PORT" -} - -function install_docker() { - sudo apt-get update - sudo apt-get install docker.io - echo -e "\n${COLOR_GREEN}Docker installed successfully.${COLOR_RESET}" - if [ ! -f "docker-compose.yml" ]; then - if [ ! -f "docker-compose.yml.example" ]; then - echo "Couldn't find example Docker Compose file" - else - sudo cp docker-compose.yml.example docker-compose.yml - echo -e "${COLOR_GREEN}Done!${COLOR_RESET}" - fi - else - echo -e "${COLOR_GREEN}Docker Compose file already exists, skipping.${COLOR_RESET}" - fi - echo -e "${COLOR_BLUE}Creating Docker network...${COLOR_RESET}" - if ! sudo docker network inspect aidxnfun-n >/dev/null 2>&1; then - sudo docker network create --subnet=10.5.0.0/16 aidxnfun-n >/dev/null 2>&1 - echo "${COLOR_GREEN}Created Docker network.${COLOR_RESET}" - else - echo "${COLOR_YELLOW}Docker network already exists.${COLOR_RESET}" - fi -} - function install_tools() { - if ! command -v curl &> /dev/null 2>&1; then - echo -e "${COLOR_RED}curl is not installed. Installing now...${COLOR_RESET}" - echo -e "${COLOR_YELLOW}You may need to enter your sudo password.${COLOR_RESET}\n" - sudo apt-get install curl - echo -e "\n${COLOR_GREEN}curl installed successfully.${COLOR_RESET}\n" - else - echo -e "${COLOR_GREEN}curl is installed.${COLOR_RESET}" - fi - if ! command -v node &> /dev/null 2>&1; then echo -e "${COLOR_RED}NodeJS is not installed. Installing now...${COLOR_RESET}" echo -e "${COLOR_YELLOW}You may need to enter your sudo password.${COLOR_RESET}\n" @@ -69,15 +33,6 @@ function install_tools() { echo -e "${COLOR_GREEN}Netcat is installed.${COLOR_RESET}" fi - if ! command -v docker &> /dev/null 2>&1; then - echo -e "${COLOR_RED}Docker is not installed. Installing now...${COLOR_RESET}" - echo -e "${COLOR_YELLOW}You may need to enter your sudo password.${COLOR_RESET}\n" - install_docker - echo -e "\n${COLOR_GREEN}Docker installed successfully.${COLOR_RESET}\n" - else - echo -e "${COLOR_GREEN}Docker is installed. Version: $(docker --version)${COLOR_RESET}" - fi - if ! command -v npm &> /dev/null 2>&1; then echo -e "${COLOR_RED}NPM is not installed. Installing now...${COLOR_RESET}" echo -e "${COLOR_YELLOW}You may need to enter your sudo password.${COLOR_RESET}\n" @@ -88,13 +43,13 @@ function install_tools() { if [ ! -f "config.json.example" ]; then echo "Couldn't find example config file" else - sudo cp config.json.example config.json + cp config.json.example config.json fi else echo -e "${COLOR_GREEN}config file already exists, skipping.${COLOR_RESET}" fi echo -e "${COLOR_BLUE}Installing NPM deps...${COLOR_RESET}" - npm install > node.log 2>&1 + npm install echo -e "\n${COLOR_GREEN}NPM installed successfully.${COLOR_RESET}\n" touch $SETUP_FILE else @@ -112,8 +67,6 @@ function show_help() { echo -e " ${COLOR_CYAN}down${COLOR_RESET} Stops the server." echo -e " ${COLOR_CYAN}restart${COLOR_RESET} Restarts the server." echo -e " ${COLOR_CYAN}status, -s, --status${COLOR_RESET} Checks if the server is running.\n" - echo -e "${COLOR_YELLOW}Options:${COLOR_RESET}" - echo -e " ${COLOR_CYAN}--db-alive${COLOR_RESET} Do not restart Docker services.\n" } function check_dirs() { @@ -155,48 +108,32 @@ function check_dirs() { function restart_server() { check_setup - if [ "$DB_ALIVE" == "true" ]; then - echo -e "${COLOR_YELLOW}Database services will not be restarted. Skipping Docker operations.${COLOR_RESET}" - else - if [ -d './public' ]; then - echo -e "${COLOR_BLUE}Deleting public directories...${COLOR_RESET}" - check_dirs "delete" - fi + if [ -d './public' ]; then + echo -e "${COLOR_BLUE}Deleting public directories...${COLOR_RESET}" + check_dirs "delete" + fi - if [ -f './src/css/main.css' ]; then - echo -e "${COLOR_BLUE}Deleting old Tailwind CSS...${COLOR_RESET}" - rm ./src/css/main.css - echo -e "${COLOR_GREEN}Done.${COLOR_RESET}" - fi - - PIDS=$(lsof -t -i:$PORT) - - if [ -n "$PIDS" ]; then - echo -e "${COLOR_BLUE}Stopping server...${COLOR_RESET}" - for PID in $PIDS; do - kill "$PID" || echo -e "${COLOR_RED}Failed to kill PID: $PID${COLOR_RESET}" - done - echo -e "${COLOR_GREEN}Done.${COLOR_RESET}" - else - echo -e "${COLOR_YELLOW}No process found on port $PORT.${COLOR_RESET}" - fi - - echo -e "${COLOR_BLUE}Stopping database...${COLOR_RESET}" - echo "This may require your sudo password" - sudo docker compose down - echo -e "${COLOR_GREEN}Done.${COLOR_RESET}" - - echo -e "${COLOR_BLUE}Creating public directories...${COLOR_RESET}" - check_dirs "create" - - echo -e "${COLOR_BLUE}Starting database...${COLOR_RESET}" - echo "This may require your sudo password" - sudo docker compose up -d - echo -e "${COLOR_BLUE}Waiting 30 seconds for database startup...${COLOR_RESET}" - sleep 30 + if [ -f './src/css/main.css' ]; then + echo -e "${COLOR_BLUE}Deleting old Tailwind CSS...${COLOR_RESET}" + rm ./src/css/main.css echo -e "${COLOR_GREEN}Done.${COLOR_RESET}" fi + PIDS=$(lsof -t -i:$PORT) + + if [ -n "$PIDS" ]; then + echo -e "${COLOR_BLUE}Stopping server...${COLOR_RESET}" + for PID in $PIDS; do + kill "$PID" || echo -e "${COLOR_RED}Failed to kill PID: $PID${COLOR_RESET}" + done + echo -e "${COLOR_GREEN}Done.${COLOR_RESET}" + else + echo -e "${COLOR_YELLOW}No process found on port $PORT.${COLOR_RESET}" + fi + + echo -e "${COLOR_BLUE}Creating public directories...${COLOR_RESET}" + check_dirs "create" + echo -e "${COLOR_BLUE}Building project...${COLOR_RESET}" if ! npm run build > node.log 2>&1; then echo -e "${COLOR_RED}Build failed. Please check for errors above.${COLOR_RESET}" @@ -219,27 +156,23 @@ function restart_server() { echo -e "${COLOR_BLUE}Starting server...${COLOR_RESET}" npm start > node.log 2>&1 & - echo -e "${COLOR_GREEN}Done. Server up and running on port $PORT!${COLOR_RESET}" + sleep 1 + + PIDS=$(lsof -t -i:$PORT) + if [ -n "$PIDS" ]; then + echo -e "${COLOR_GREEN}\nDone. Server up and running on port $PORT!\n${COLOR_RESET}" + else + echo -e "${COLOR_RED}Something went wrong... Check node.log for more details${COLOR_RESET} (no process on port)" + fi } function start_server() { check_setup - if [ "$DB_ALIVE" == "true" ]; then - echo -e "${COLOR_YELLOW}Database services will not be restarted. Skipping Docker operations.${COLOR_RESET}" - else - echo -e "${COLOR_BLUE}Starting database...${COLOR_RESET}" - echo "This may require your sudo password" - sudo docker compose up -d - echo -e "${COLOR_BLUE}Waiting 30 seconds for database startup...${COLOR_RESET}" - sleep 30 - echo -e "${COLOR_GREEN}Done.${COLOR_RESET}" - fi - PID=$(lsof -t -i:$PORT) if [ -n "$PID" ]; then - echo -e "${COLOR_YELLOW}Server process already running on port $PORT. Skipping server start.${COLOR_RESET}" + echo -e "${COLOR_YELLOW}Server already running on port $PORT. Skipping server startup.${COLOR_RESET}" return fi @@ -274,22 +207,20 @@ function start_server() { echo -e "${COLOR_BLUE}Starting server...${COLOR_RESET}" npm start > node.log 2>&1 & - echo -e "${COLOR_GREEN}Done. Server up and running on port $PORT!${COLOR_RESET}" + sleep 1 + + PIDS=$(lsof -t -i:$PORT) + if [ -n "$PIDS" ]; then + echo -e "${COLOR_GREEN}\nDone. Server up and running on port $PORT!\n${COLOR_RESET}" + else + echo -e "${COLOR_RED}Something went wrong... Check node.log for more details${COLOR_RESET} (no process on port)" + fi } function stop_server() { check_setup PID=$(lsof -t -i:$PORT) - if [ "$DB_ALIVE" == "true" ]; then - echo -e "${COLOR_YELLOW}Database services will not be stopped. Skipping Docker operations.${COLOR_RESET}" - else - echo -e "${COLOR_BLUE}Stopping database...${COLOR_RESET}" - echo "This may require your sudo password" - sudo docker compose down - echo -e "${COLOR_GREEN}Done.${COLOR_RESET}" - fi - if [ -d './public' ]; then echo -e "${COLOR_BLUE}Deleting public directories...${COLOR_RESET}" check_dirs "delete" @@ -340,12 +271,12 @@ function setup() { read -n 1 -s -r -p "" clear - echo -e "This script requires Node.js, NPM, and Docker to be installed on your system." + echo -e "This script requires Node.js, NPM, and Netcat to be installed on your system." echo "Please ensure you have these tools installed before proceeding." echo -e "\nPress any key to continue with tool installation..." read -n 1 -s -r -p "" - clear + install_tools echo -e "\n${COLOR_GREEN}Dependancy installation complete!${COLOR_RESET}" @@ -359,8 +290,7 @@ function setup() { read -n 1 -s -r -p "" clear - echo -e "${COLOR_BLUE}Now, you should disconnect your SSH session or logout from your computer, and reconnect/login again for the best results.${COLOR_RESET}" - echo -e "\n${COLOR_BLUE}Then, start the server with this command:${COLOR_RESET}" + echo -e "${COLOR_BLUE}Now, you may start the server with this command:${COLOR_RESET}" echo -e "${COLOR_GREEN}./manage up${COLOR_RESET}\n" echo -e "\n${COLOR_BLUE}If you need help, or to get info about other commands, simply use:${COLOR_RESET}" echo -e "${COLOR_GREEN}./manage help${COLOR_RESET}" @@ -377,19 +307,6 @@ function check_setup() { fi } -DB_ALIVE="false" -if [[ $# -eq 0 ]]; then - show_help - exit 0 -fi - -for arg in "$@"; do - if [[ "$arg" == "--db-alive" ]]; then - DB_ALIVE="true" - break - fi -done - case $1 in up) check_setup diff --git a/postcss.config.js b/postcss.config.js deleted file mode 100644 index e69de29..0000000 diff --git a/views/about.ejs b/views/about.ejs index 31f7761..2703f0d 100644 --- a/views/about.ejs +++ b/views/about.ejs @@ -69,8 +69,5 @@

You can learn more about my opinions on cloud platforms on this page.

-
- <%- include('shards/views.ejs') %> -
<%- include('shards/footer.ejs') %> \ No newline at end of file diff --git a/views/cloud.ejs b/views/cloud.ejs index 281b976..880be75 100644 --- a/views/cloud.ejs +++ b/views/cloud.ejs @@ -38,8 +38,5 @@ -
- <%- include('shards/views.ejs') %> -
<%- include('shards/footer.ejs') %> \ No newline at end of file diff --git a/views/contact.ejs b/views/contact.ejs index 004c6f1..83d16a5 100644 --- a/views/contact.ejs +++ b/views/contact.ejs @@ -41,8 +41,5 @@ -
- <%- include('shards/views.ejs') %> -
<%- include('shards/footer.ejs') %> diff --git a/views/index.ejs b/views/index.ejs index e20cda3..8d3e557 100644 --- a/views/index.ejs +++ b/views/index.ejs @@ -47,7 +47,6 @@

Some of my favorite artists include tobi lou, Skizzy Mars, and Kali Uchis. Some of my classics are Mike Stud (before his name change to "mike."), Skizzy Mars, tobi lou, The Neighbourhood, and Ryan Caraveo.

-<%- include('shards/views.ejs') %> <%- include('shards/footer.ejs') %> \ No newline at end of file diff --git a/views/projects.ejs b/views/projects.ejs index d799f5c..9b5c2fe 100644 --- a/views/projects.ejs +++ b/views/projects.ejs @@ -40,8 +40,5 @@

Finished projects

I currently have only one public project which is in finished state. It's my old website, which is now being hosted at old.aidxn.fun. It features a 2000s design and flashy graphics!

-
- <%- include('shards/views.ejs') %> -
<%- include('shards/footer.ejs') %> \ No newline at end of file diff --git a/views/shards/views.ejs b/views/shards/views.ejs deleted file mode 100644 index e05cb56..0000000 --- a/views/shards/views.ejs +++ /dev/null @@ -1,16 +0,0 @@ -
-

Analytics

-

Our analytics system does not track you, ever. Only a simple counter is used, and your IP address is never stored or shared.

-

Total Views: 0

-
- \ No newline at end of file diff --git a/views/status.ejs b/views/status.ejs index 5db33b8..914d89b 100644 --- a/views/status.ejs +++ b/views/status.ejs @@ -27,9 +27,6 @@

Status | Backend

[UNKNOWN - LOADING ms] kantor.aidxn.fun (Oracle Cloud - Germany - backend server)

-
- <%- include('shards/views.ejs') %> -
<%- include('shards/footer.ejs') %> \ No newline at end of file diff --git a/views/verify.ejs b/views/verify.ejs index b404a4a..a3b79c3 100644 --- a/views/verify.ejs +++ b/views/verify.ejs @@ -26,8 +26,5 @@

Check Message

THIS FORM IS NOT CURRENTLY AVAILABLE

-
- <%- include('shards/views.ejs') %> -
<%- include('shards/footer.ejs') %> \ No newline at end of file