commit 5fc35b2f76b7b31ebde67a5387cd405f98ed6cd1 Author: sapient Date: Sun Mar 22 00:54:28 2026 -0700 chore: initial commit of Server Configs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a54a397 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.env +.env.* +*.log +node_modules/ +.venv/ diff --git a/httpserver/AUDIT.md b/httpserver/AUDIT.md new file mode 100644 index 0000000..eb1dbf8 --- /dev/null +++ b/httpserver/AUDIT.md @@ -0,0 +1,149 @@ +# Code Audit Report — httpserver stack + +**Date:** 2026-03-05 +**Scope:** `/opt/stacks/httpserver` (compose, data/, chat server, services loader, static assets) + +--- + +## Executive summary + +- **Security:** Several issues: sensitive file exposure, client-side XSS risk in chat, missing escaping in services HTML, no chat rate limiting or abuse controls. +- **Correctness:** One protocol mismatch (gs.html chat history never populates). +- **Maintainability:** Minor issues (comment vs script name, dependency pinning). + +--- + +## 1. Security + +### 1.1 Sensitive file served as static content (High) + +**File:** `data/banned.json` +**Issue:** The entire `data/` directory is mounted as the Apache document root (`./data:/var/www/html`). So `banned.json` is publicly reachable at `/banned.json`. It contains fail2ban-style jail names and IP addresses. + +**Impact:** Information disclosure (internal IPs, jail names). Useful for reconnaissance. + +**Recommendation:** + +- Move `banned.json` outside the web root (e.g. project root or a non-served volume) if it must live in the repo, **or** +- Exclude it from the volume used as document root (e.g. serve only a whitelisted subdirectory), **or** +- Stop serving it over HTTP (e.g. use it only in a backend/script that doesn’t expose it). + +### 1.2 Chat client uses `innerHTML` for message text (Medium) + +**File:** `data/chat.js` (around line 102) + +```javascript +// Comment says "use textContent for safety" but code uses innerHTML: +textSpan.innerHTML = msg.text; +``` + +**Issue:** The server sanitizes only `<` and `>` in `chat-server.js`. Using `innerHTML` with server output is fragile: if sanitization is ever relaxed or bypassed, or if the client receives data from another path, this becomes an XSS sink. + +**Recommendation:** Use `textContent` for the message body so the DOM is not parsed as HTML. If you need newlines, use `textContent` and style with `white-space: pre-wrap` (or similar). + +### 1.3 Services HTML built from JSON without escaping (Medium) + +**File:** `data/services-loader.js` +**Issue:** Service `name`, `url`, `category`, and `meta[].label` / `meta[].url` are interpolated into HTML strings (e.g. `href="${meta.url}"`, `${service.name}`) without encoding. If `services-data.json` is ever edited incorrectly, compromised, or merged with untrusted data, a value containing `"` or `>` could break attributes or inject script. + +**Recommendation:** Add a small `escapeHtml` (and optionally `escapeAttr`) helper and use it for every value that is inserted into HTML or attributes. Keep treating `services-data.json` as trusted input, but defense-in-depth avoids mistakes and future data sources. + +### 1.4 Chat server: no rate limiting or abuse controls (Medium) + +**File:** `data/chat-server.js` +**Issue:** Any client can connect and send unlimited messages. There is no per-IP or per-connection rate limit, no use of `banned.json`, and no max message size beyond the 200-character sanitizer slice. + +**Impact:** DoS via message flood; spam; possible memory pressure from a very large `history` if `HISTORY_MAX` is raised. + +**Recommendation:** Add rate limiting (e.g. per connection: max N messages per minute). Optionally enforce max message size and consider using `banned.json` (or a similar list) to reject connections from banned IPs if the proxy passes client IP (e.g. via `X-Forwarded-For` and a trusted proxy config). + +### 1.5 Chat sanitization is minimal (Low) + +**File:** `data/chat-server.js` — `sanitize()` +**Issue:** Only `<` and `>` are escaped. For plain text in a `
` (and if the client uses `textContent` as recommended), this is enough for basic XSS prevention. It does not normalize Unicode or protect against other edge cases (e.g. if the same string were ever used in an attribute). + +**Recommendation:** Keep server-side sanitization and switch the client to `textContent`. If you later use the same string in attributes or other contexts, add encoding appropriate to that context (e.g. attribute encoding). + +--- + +## 2. Correctness + +### 2.1 Chat history protocol mismatch in gs.html (Bug) + +**Files:** `data/chat-server.js` vs `data/gs.html` +**Issue:** The server sends history as: + +```javascript +{ type: 'history', messages: history } +``` + +`gs.html` expects: + +```javascript +if (Array.isArray(msg.history)) { ... } +``` + +So `msg.history` is always undefined and chat history is never shown on the GS page. + +**Recommendation:** In `gs.html`, use `msg.messages` when `data.type === 'history'` (and optionally check `Array.isArray(msg.messages)`), consistent with `chat.js`. + +--- + +## 3. Configuration & deployment + +### 3.1 Apache proxy config duplication + +**File:** `data/chat-proxy.conf` +**Issue:** Both `RewriteRule` and `ProxyPass`/`ProxyPassReverse` are used for `/chat` → WebSocket. This can be redundant or confusing; one consistent mechanism (e.g. mod_rewrite with `[P]` or ProxyPass) is easier to reason about. + +**Recommendation:** Prefer one approach (e.g. RewriteRule with `[P,L]` for WebSocket upgrade, and ensure no double proxy). Document which Apache modules are required. + +### 3.2 Chat server port exposure + +**File:** `compose.yaml` +**Issue:** The chat service publishes `8098:8081`. So the WebSocket server is reachable on host port 8098 without going through Apache. If Apache is the intended single entry point for the site, consider not publishing the chat port on the host (only expose it on `internal-net` so Apache can proxy to it). + +**Recommendation:** Remove the `ports:` mapping for the chat service if all access should be via Apache’s `/chat`; otherwise document that 8098 is intentionally public. + +### 3.3 Dependency pinning + +**File:** `data/package.json` +**Issue:** `"ws": "^8.18.0"` allows minor/patch updates. Rebuilds can pull different versions. + +**Recommendation:** Use exact versions (e.g. `"ws": "8.18.0"`) or lock with `package-lock.json` committed and `npm ci` in the image for reproducible builds. + +--- + +## 4. Maintainability + +### 4.1 Outdated comment / missing script + +**File:** `data/services-loader.js` (header comment) +**Issue:** Historical note: the loader previously had an embedded-data workflow and referenced a script for syncing/embedding. + +**Recommendation:** Keep `services-data.json` as the single source of truth and load it at runtime (no embed/sync step). + +--- + +## 5. Positive notes + +- Chat server sanitizes nickname and message length and strips `<`/`>`. +- `gs.html` uses an `escapeHtml` helper for chat nick and text when building HTML. +- `main.js` respects `prefers-reduced-motion` and limits star count on small viewports. +- Compose resource limits and logging options are set; networks are isolated. +- `.env` in project root is not under the web root, so it is not served. + +--- + +## 6. Summary of recommended actions (all applied) + +| Priority | Item | Status | +|----------|------|--------| +| High | Stop serving `banned.json` | Done: Apache ` Require all denied` in `chat-proxy.conf` | +| Medium | In `chat.js`, use `textContent` for message text | Done | +| Medium | In `services-loader.js`, escape all dynamic values | Done: `escapeHtml` / `escapeAttr` added and used | +| Medium | Add rate limiting to chat server | Done: 30 msg/min per connection (configurable via `CHAT_RATE_LIMIT`) | +| Medium | Fix `gs.html` to use `msg.messages` for history | Done | +| Low | Simplify Apache proxy config and document | Done: comment + deny for banned.json | +| Low | Do not publish chat port; use Apache only | Done: port removed; `gs.html` uses `location.host + '/chat'` | +| Low | Pin `ws`; fix `services-loader.js` comment | Done: `"ws": "8.18.0"`; loader now reads `services-data.json` directly (no status/embed script). | diff --git a/httpserver/compose.yaml b/httpserver/compose.yaml new file mode 100644 index 0000000..b723122 --- /dev/null +++ b/httpserver/compose.yaml @@ -0,0 +1,99 @@ +name: httpserver +x-logging: &a1 + driver: json-file + options: + max-size: 10m + max-file: "3" +services: + http1: + image: php:8.2-apache + container_name: http1 + restart: unless-stopped + environment: + - TZ=America/Los_Angeles + volumes: + - ./data:/var/www/html + - ./data/gw.html:/var/www/html/index.html + - ./data/chat-proxy.conf:/etc/apache2/conf-enabled/chat-proxy.conf + command: > + bash -c "a2enmod proxy proxy_http proxy_wstunnel rewrite && + apache2-foreground" + ports: + - 9797:80 + healthcheck: + test: + - CMD-SHELL + - curl -fs http://127.0.0.1:80/ || exit 1 + interval: 15s + timeout: 5s + retries: 5 + deploy: + resources: + limits: + cpus: "0.25" + memory: 128M + reservations: + cpus: "0.05" + memory: 32M + logging: *a1 + http2: + image: php:8.2-apache + container_name: http2 + restart: unless-stopped + environment: + - TZ=America/Los_Angeles + volumes: + - ./data:/var/www/html + - ./data/ugh.html:/var/www/html/index.html + - ./data/chat-proxy.conf:/etc/apache2/conf-enabled/chat-proxy.conf + command: > + bash -c "a2enmod proxy proxy_http proxy_wstunnel rewrite && + apache2-foreground" + ports: + - 9798:80 + healthcheck: + test: + - CMD-SHELL + - curl -fs http://127.0.0.1:80/ || exit 1 + interval: 15s + timeout: 5s + retries: 5 + deploy: + resources: + limits: + cpus: "0.25" + memory: 128M + reservations: + cpus: "0.05" + memory: 32M + logging: *a1 + chat-server: + image: node:22-alpine + working_dir: /app + restart: unless-stopped + environment: + - CHAT_LOG_PATH=/app/messages.log + volumes: + - ./data:/app + command: sh -c "npm install --omit=dev && node chat-server.js" + healthcheck: + test: + - CMD-SHELL + - curl -fs http://127.0.0.1:80/ || exit 1 + interval: 15s + timeout: 5s + retries: 5 + logging: + driver: json-file + options: + max-size: 10m + max-file: "3" + deploy: + resources: + limits: + cpus: "0.5" + memory: 256M + reservations: + cpus: "0.1" + memory: 64M +networks: {} diff --git a/httpserver/data/.gitignore b/httpserver/data/.gitignore new file mode 100644 index 0000000..869f9cd --- /dev/null +++ b/httpserver/data/.gitignore @@ -0,0 +1,21 @@ +# OS +.DS_Store +Thumbs.db + +# Editor/IDE +*.swp +*.swo +*~ +.idea/ +.vscode/ +*.sublime-* + +# Logs +*.log + +# Build/temp +node_modules/ +dist/ +build/ +tmp/ +.cache/ diff --git a/httpserver/data/404.html b/httpserver/data/404.html new file mode 100644 index 0000000..2e6c98d --- /dev/null +++ b/httpserver/data/404.html @@ -0,0 +1,260 @@ + + + + + + + 404 - Service Unavailable + + + + + + + +
+

404

+

Service Unavailable

+ Return to Base +
+ + + + + \ No newline at end of file diff --git a/httpserver/data/PAGES.md b/httpserver/data/PAGES.md new file mode 100644 index 0000000..86dd05d --- /dev/null +++ b/httpserver/data/PAGES.md @@ -0,0 +1,38 @@ +# Pages + +## Root structure + +- **index.html** — Redirects to `gw.html`. +- **Active pages** — `gw.html`, `ugh.html`, `gs.html`, `basic.html` (see table below). +- **Shared** — `main.js`, `services-loader.js`, `services-data.json`, `ddate-now`, `assets/`, and per-page CSS/JS. **Chat backend** — `chat-server.js`, `package.json` (Node + `ws`) for the real-time chat on **GS**. + +## Active + +| Page | File | Description | +|--------|------------|-------------| +| **GW** | `gw.html` | Main GravityWell.xYz site (standard). | +| **Ugh**| `ugh.html` | UGH.im branded, high-energy version. | +| **GS** | `gs.html` | GalaxySpin.Space experience; includes embedded real-time chat widget. | +| **Basic** | `basic.html` | Minimal HTML/CSS, no JS; good for low bandwidth and accessibility. | + +## Archive + +Non-active or alternate versions are under `archive/`: + +- **archive/standby.html** — Maintenance / standby page. +- **archive/unavailable.html** — Unavailable notice (with home link). +- **archive/future.html** (+ **archive/future.css**) — “Future” theme; loads `../services-data.json`. +- **archive/extra/** — Alternate layouts: Retro, Shelf, Icons, Bloodlust (ugh-bloodlust); `index.html` redirects to `../../gw.html`. +- **archive/GSS/** — GalaxySpin.Space theme variants (type0–type7) and `instructions.txt`. +- **archive/20260208_234428/** — Dated snapshot of GW and Ugh. +- **archive/services.json**, **archive/gs_services.json** — Legacy data (unused by active pages). + +## Chat (GS) + +**gs.html** includes an embedded real-time chat widget (bottom-right). It connects to a WebSocket server that broadcasts messages to all connected clients (no persistence). + +- **Run the chat server:** From the repo root, `npm install` then `node chat-server.js` (or `npm run chat`). Listens on port **8081** by default; set `CHAT_PORT` to override. +- **Docker:** When deployed via the stack at `/opt/stacks/httpsimple`, a second service `chat-server` runs the Node server; the compose file exposes the WebSocket on port **8098**. +- **WebSocket URL (frontend):** Configurable so the same page works locally and behind a reverse proxy. + - **Default:** `ws://:8098` (or `wss://` if the page is served over HTTPS). Use when the chat server is reachable on port 8098. + - **Override:** Set `window.CHAT_WS_URL` before the chat script runs, or set `data-ws-url` on `` (e.g. `data-ws-url="wss://galaxyspin.space/chat-ws"` when proxying). diff --git a/httpserver/data/assets/BTC.webp b/httpserver/data/assets/BTC.webp new file mode 100755 index 0000000..6e7838a Binary files /dev/null and b/httpserver/data/assets/BTC.webp differ diff --git a/httpserver/data/assets/DOGE.webp b/httpserver/data/assets/DOGE.webp new file mode 100755 index 0000000..158d609 Binary files /dev/null and b/httpserver/data/assets/DOGE.webp differ diff --git a/httpserver/data/assets/XMR.webp b/httpserver/data/assets/XMR.webp new file mode 100755 index 0000000..840ee4f Binary files /dev/null and b/httpserver/data/assets/XMR.webp differ diff --git a/httpserver/data/assets/disabled.mp4.mp4 b/httpserver/data/assets/disabled.mp4.mp4 new file mode 100644 index 0000000..5f8f73f Binary files /dev/null and b/httpserver/data/assets/disabled.mp4.mp4 differ diff --git a/httpserver/data/assets/disabled_.mp4 b/httpserver/data/assets/disabled_.mp4 new file mode 100644 index 0000000..1e55f57 Binary files /dev/null and b/httpserver/data/assets/disabled_.mp4 differ diff --git a/httpserver/data/assets/favicon.webp b/httpserver/data/assets/favicon.webp new file mode 100755 index 0000000..797b2f0 Binary files /dev/null and b/httpserver/data/assets/favicon.webp differ diff --git a/httpserver/data/assets/standby.gif b/httpserver/data/assets/standby.gif new file mode 100644 index 0000000..89f0d2e Binary files /dev/null and b/httpserver/data/assets/standby.gif differ diff --git a/httpserver/data/assets/standby.jpg b/httpserver/data/assets/standby.jpg new file mode 100644 index 0000000..f4123ec Binary files /dev/null and b/httpserver/data/assets/standby.jpg differ diff --git a/httpserver/data/assets/standby.mp4 b/httpserver/data/assets/standby.mp4 new file mode 100644 index 0000000..6f7ca05 Binary files /dev/null and b/httpserver/data/assets/standby.mp4 differ diff --git a/httpserver/data/assets/standby.png b/httpserver/data/assets/standby.png new file mode 100644 index 0000000..3b8b0b8 Binary files /dev/null and b/httpserver/data/assets/standby.png differ diff --git a/httpserver/data/assets/standby.webp b/httpserver/data/assets/standby.webp new file mode 100644 index 0000000..fcc703a Binary files /dev/null and b/httpserver/data/assets/standby.webp differ diff --git a/httpserver/data/banned.json b/httpserver/data/banned.json new file mode 100644 index 0000000..9e4e8bd --- /dev/null +++ b/httpserver/data/banned.json @@ -0,0 +1,24 @@ +{ + "last_updated": "2026-01-28 21:15:01", + "jails": { + "sshd": [ + "182.43.235.218", + "93.71.118.99" + ], + "recidive": [ + "176.120.22.13", + "209.38.21.233", + "80.94.92.182", + "80.94.92.186" + ], + "nginx-env-aggressive": [], + "python-scanner": [ + "185.209.196.236", + "4.194.156.15" + ], + "nginx-bot-signature": [], + "npm-attacks": [], + "npm-traffic": [] + }, + "total_ips": 8 +} \ No newline at end of file diff --git a/httpserver/data/basic.css b/httpserver/data/basic.css new file mode 100644 index 0000000..af63321 --- /dev/null +++ b/httpserver/data/basic.css @@ -0,0 +1,213 @@ +/* Basic — minimal, readable, no-JS-friendly */ +:root { + --bg: #0f0f0f; + --text: #e0e0e0; + --muted: #888; + --accent: #6a9fb5; + --link: #7cb8d4; + --border: #333; +} + +* { + box-sizing: border-box; +} + +body { + font-family: system-ui, -apple-system, Segoe UI, sans-serif; + background: var(--bg); + color: var(--text); + line-height: 1.6; + max-width: 52rem; + margin: 0 auto; + padding: 1rem 1.5rem; +} + +header { + text-align: center; + margin-bottom: 1.5rem; +} + +header h1 { + font-size: 1.5rem; + letter-spacing: 0.15em; + margin: 0 0 0.5rem; +} + +header p { + margin: 0.25rem 0; + color: var(--muted); + font-size: 0.95rem; +} + +nav ul { + list-style: none; + margin: 0; + padding: 0; + display: flex; + flex-wrap: wrap; + gap: 0.5rem 1rem; + justify-content: center; +} + +nav a { + color: var(--link); + text-decoration: none; +} + +nav a:hover { + text-decoration: underline; +} + +.versions { + margin: 0.75rem 0; + padding: 0.5rem 0; + border-top: 1px solid var(--border); + border-bottom: 1px solid var(--border); + font-size: 0.9rem; + text-align: center; +} + +.versions a { + color: var(--accent); + text-decoration: none; + margin: 0 0.5rem; +} + +.versions a:hover { + text-decoration: underline; +} + +hr { + border: none; + border-top: 1px solid var(--border); + margin: 1.5rem 0; +} + +main section { + margin-bottom: 1rem; +} + +h2 { + font-size: 1.15rem; + margin: 1.25rem 0 0.5rem; + color: var(--text); +} + +h3 { + font-size: 1rem; + margin: 1rem 0 0.4rem; + color: var(--muted); +} + +p { + margin: 0.5rem 0; +} + +ul { + margin: 0.5rem 0; + padding-left: 1.5rem; +} + +li { + margin: 0.25rem 0; +} + +a { + color: var(--link); + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +/* Maintenance Status */ +.status-maintenance { + opacity: 0.6; + pointer-events: none; +} + +/* Back-compat: treat "down" the same as prior "maintenance" */ +.status-down { + opacity: 0.6; + pointer-events: none; +} + +.status-maintenance a { + text-decoration: line-through !important; + color: var(--muted) !important; +} + +.status-down a { + text-decoration: line-through !important; + color: var(--muted) !important; +} + +.maintenance-badge { + font-size: 0.8em; + color: #e74c3c; + margin-left: 0.5rem; + font-weight: bold; +} + +code { + background: #1a1a1a; + padding: 0.15em 0.4em; + border-radius: 3px; + font-size: 0.9em; + word-break: break-all; +} + +#guest-info { + background: #1a1a1a; + padding: 0.75rem 1rem; + border-radius: 4px; + margin-bottom: 1rem; +} + +#guest-info small { + color: var(--muted); +} + +footer { + text-align: center; + font-size: 0.9rem; + color: var(--muted); + margin-top: 2rem; + padding-top: 1rem; +} + +footer a { + color: var(--accent); +} + +.footer-links ul { + display: flex; + flex-wrap: wrap; + gap: 0.5rem 1rem; + list-style: none; + padding-left: 0; +} + +.footer-links li { + margin: 0; +} + +@media (prefers-color-scheme: light) { + :root { + --bg: #f5f5f5; + --text: #1a1a1a; + --muted: #555; + --accent: #2d6a7a; + --link: #1a5f7a; + --border: #ccc; + } + + code { + background: #e8e8e8; + } + + #guest-info { + background: #e8e8e8; + } +} \ No newline at end of file diff --git a/httpserver/data/basic.html b/httpserver/data/basic.html new file mode 100644 index 0000000..8cedf05 --- /dev/null +++ b/httpserver/data/basic.html @@ -0,0 +1,232 @@ + + + + + + + GravityWell.xYz (Basic) + + + + + + + +
+

GRAVITYWELL.xYz

+

Self-Hosting is killing corporate profits!

+

We left these services open so you can help.

+
+ +
+ + + +
+ +
+
+

About This Space

+

An experiment in self-hosting, data archiving, and community building.

+

Most services here are open to new users and connected with the Fediverse. All services are running on + home infrastructure and a cheap VPS.

+ +

Recommended Extensions

+

The following browser extensions have been known to cause problems for surveillance capitalism and as + such have been banned by Google, but you can still use them!

+ +
+ +
+ +
+

Community

+ +
+ +
+ +
+

Contact

+ +
+ +
+ +
+

Services

+ +
+

Guest Access Info

+

Some services don't have a sign-up option. Use the guest account to try them out.

+
    +
  • USER: gwguest
  • +
  • PASS: gravitywell.xyz
  • +
+

* GravityWell.xYz services hosted on home server.
* ugh.im services hosted on VPS.
+

+
+ +

Multimedia

+ + +

Audio Streaming

+ + +

Games & Emulation

+ + +

Fediverse

+ + +

Communications

+ + +

Privacy Front Ends

+ + +

Office & Productivity

+ + +

Utilities

+ +
+ +
+ + + +
+ + + +
+ +
+ + + + + + diff --git a/httpserver/data/bgmusic.opus b/httpserver/data/bgmusic.opus new file mode 100644 index 0000000..b7aa81d Binary files /dev/null and b/httpserver/data/bgmusic.opus differ diff --git a/httpserver/data/chat-proxy.conf b/httpserver/data/chat-proxy.conf new file mode 100644 index 0000000..d9c97a7 --- /dev/null +++ b/httpserver/data/chat-proxy.conf @@ -0,0 +1,23 @@ +# WebSocket proxy: /chat -> chat-server:8081 +# Requires: proxy, proxy_http, proxy_wstunnel, rewrite +LoadModule proxy_module modules/mod_proxy.so +LoadModule proxy_http_module modules/mod_proxy_http.so +LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so + +ProxyRequests Off +ProxyPreserveHost On + +# Deny direct access to sensitive files (e.g. banned.json) if present in docroot + + + Require all denied + + + +# Single mechanism: ProxyPass for WebSocket upgrade and initial request +RewriteEngine On +RewriteCond %{HTTP:Upgrade} =websocket [NC] +RewriteRule ^/chat$ ws://chat-server:8081/ [P,L] +RewriteRule ^/chat ws://chat-server:8081/ [P,L] +ProxyPass /chat ws://chat-server:8081/ +ProxyPassReverse /chat ws://chat-server:8081/ diff --git a/httpserver/data/chat-server.js b/httpserver/data/chat-server.js new file mode 100644 index 0000000..7e9241f --- /dev/null +++ b/httpserver/data/chat-server.js @@ -0,0 +1,201 @@ +#!/usr/bin/env node +'use strict'; + +const { WebSocketServer } = require('ws'); +const fs = require('fs'); +const path = require('path'); + +const PORT = Number(process.env.CHAT_PORT) || 8081; +const HISTORY_MAX = Math.max(1, Math.min(1000, Number(process.env.CHAT_HISTORY_MAX) || 100)); +const RATE_LIMIT_WINDOW_MS = 60 * 1000; +const RATE_LIMIT_MAX_MESSAGES = Number(process.env.CHAT_RATE_LIMIT) || 30; +const DEFAULT_LOG_DIR = __dirname; +const LOG_PATH = process.env.CHAT_LOG_PATH + ? path.resolve(process.env.CHAT_LOG_PATH) + : path.join(DEFAULT_LOG_DIR, 'messages.log'); + +const clients = new Set(); +const history = []; +const connectionMessageCount = new WeakMap(); +const connectionWindowStart = new WeakMap(); +const connectionNickSuffix = new WeakMap(); + +function getClientIp(req) { + const xff = req && req.headers ? req.headers['x-forwarded-for'] : null; + if (typeof xff === 'string' && xff.trim()) { + // May be a comma-separated list: client, proxy1, proxy2 + const first = xff.split(',')[0].trim(); + if (first) return first; + } + const realIp = req && req.headers ? req.headers['x-real-ip'] : null; + if (typeof realIp === 'string' && realIp.trim()) return realIp.trim(); + const ra = req && req.socket ? req.socket.remoteAddress : null; + return typeof ra === 'string' && ra ? ra : ''; +} + +function last3DigitsOfIp(ip) { + const digits = String(ip || '').replace(/\D/g, ''); + return digits.slice(-3).padStart(3, '0'); +} + +function sanitizeNickBase(str) { + if (typeof str !== 'string') return ''; + // Keep it short; we append 3 digits after. + return str.trim().slice(0, 20).replace(//g, '>'); +} + +function loadHistoryFromLog() { + // Read the log as newline-delimited JSON and keep the last HISTORY_MAX entries. + // Uses a ring buffer so it can handle large logs without loading everything. + try { + if (!fs.existsSync(LOG_PATH)) return; + } catch (_) { + return; + } + + const ring = new Array(HISTORY_MAX); + let count = 0; + let buf = ''; + + try { + const fd = fs.openSync(LOG_PATH, 'r'); + try { + const chunk = Buffer.allocUnsafe(64 * 1024); + let bytesRead = 0; + let pos = 0; + // Stream through the file in chunks (simple forward scan). + while ((bytesRead = fs.readSync(fd, chunk, 0, chunk.length, pos)) > 0) { + pos += bytesRead; + buf += chunk.subarray(0, bytesRead).toString('utf8'); + let idx; + while ((idx = buf.indexOf('\n')) !== -1) { + const line = buf.slice(0, idx); + buf = buf.slice(idx + 1); + const trimmed = line.trim(); + if (!trimmed) continue; + let obj; + try { + obj = JSON.parse(trimmed); + } catch (_) { + continue; + } + if (!obj || typeof obj.nick !== 'string' || typeof obj.text !== 'string') continue; + const entry = { + nick: sanitize(obj.nick || 'Visitor'), + text: sanitize(obj.text || '').trim(), + ts: Number.isFinite(obj.ts) ? obj.ts : Date.now(), + }; + if (!entry.text) continue; + ring[count % HISTORY_MAX] = entry; + count++; + } + } + } finally { + fs.closeSync(fd); + } + } catch (err) { + console.error('Failed to read message log for history:', err && err.message ? err.message : err); + return; + } + + // Flush any partial final line (no trailing newline). + const last = buf.trim(); + if (last) { + try { + const obj = JSON.parse(last); + if (obj && typeof obj.nick === 'string' && typeof obj.text === 'string') { + const entry = { + nick: sanitize(obj.nick || 'Visitor'), + text: sanitize(obj.text || '').trim(), + ts: Number.isFinite(obj.ts) ? obj.ts : Date.now(), + }; + if (entry.text) { + ring[count % HISTORY_MAX] = entry; + count++; + } + } + } catch (_) {} + } + + const total = Math.min(count, HISTORY_MAX); + const start = count > HISTORY_MAX ? (count % HISTORY_MAX) : 0; + for (let i = 0; i < total; i++) { + history.push(ring[(start + i) % HISTORY_MAX]); + } +} + +function sanitize(str) { + if (typeof str !== 'string') return ''; + return str.slice(0, 200).replace(//g, '>'); +} + +function checkRateLimit(ws) { + const now = Date.now(); + let start = connectionWindowStart.get(ws); + let count = connectionMessageCount.get(ws) || 0; + if (start == null || now - start >= RATE_LIMIT_WINDOW_MS) { + start = now; + count = 0; + } + count++; + connectionWindowStart.set(ws, start); + connectionMessageCount.set(ws, count); + return count <= RATE_LIMIT_MAX_MESSAGES; +} + +function safeAppendLogLine(line) { + fs.appendFile(LOG_PATH, line + '\n', { encoding: 'utf8' }, (err) => { + if (err) console.error('Failed to append message log:', err.message); + }); +} + +const wss = new WebSocketServer({ port: PORT }, () => { + try { + fs.mkdirSync(path.dirname(LOG_PATH), { recursive: true }); + } catch (err) { + console.error('Failed to create log directory:', err && err.message ? err.message : err); + } + loadHistoryFromLog(); + console.log('Chat server listening on port', PORT); + console.log('Message log path:', LOG_PATH); +}); + +wss.on('connection', (ws, req) => { + clients.add(ws); + const ip = getClientIp(req); + const suffix = last3DigitsOfIp(ip); + connectionNickSuffix.set(ws, suffix); + if (history.length > 0) { + const payload = JSON.stringify({ type: 'history', messages: history }); + if (ws.readyState === 1) ws.send(payload); + } + + ws.on('message', (raw) => { + if (!checkRateLimit(ws)) return; + let msg; + try { + msg = JSON.parse(String(raw)); + } catch (_) { + return; + } + const suffix = connectionNickSuffix.get(ws) || '000'; + const base = sanitizeNickBase(msg.nick) || 'visitor'; + const nick = `${base}${suffix}`; + const text = sanitize(msg.text || ''); + if (!text.trim()) return; + const ts = Date.now(); + const entry = { nick, text: text.trim(), ts }; + history.push(entry); + while (history.length > HISTORY_MAX) history.shift(); + + safeAppendLogLine(JSON.stringify({ ...entry, iso: new Date(ts).toISOString() })); + + const payload = JSON.stringify(entry); + clients.forEach((client) => { + if (client.readyState === 1) client.send(payload); + }); + }); + + ws.on('close', () => clients.delete(ws)); + ws.on('error', () => clients.delete(ws)); +}); diff --git a/httpserver/data/chat.css b/httpserver/data/chat.css new file mode 100644 index 0000000..891ab9f --- /dev/null +++ b/httpserver/data/chat.css @@ -0,0 +1,179 @@ +/* chat.css */ +#chat-widget { + position: fixed; + bottom: 20px; + right: 20px; + width: 320px; + max-width: calc(100vw - 40px); + background: rgba(10, 10, 15, 0.95); + border: 2px solid var(--c-accent, #ff00ff); + border-radius: 8px; + box-shadow: 0 0 15px rgba(255, 0, 255, 0.4), inset 0 0 10px rgba(0, 255, 255, 0.1); + display: flex; + flex-direction: column; + z-index: 10000; + font-family: inherit; + color: var(--c-text, #fff); + overflow: hidden; + backdrop-filter: blur(5px); + transition: height 0.3s ease, transform 0.3s ease; +} + +#chat-widget.collapsed { + height: 40px !important; + cursor: pointer; +} + +#chat-header { + background: linear-gradient(90deg, #2b00ff, #ff00ff); + color: white; + padding: 10px; + font-weight: bold; + display: flex; + justify-content: space-between; + align-items: center; + user-select: none; + border-bottom: 1px solid rgba(255,255,255,0.2); +} + +#chat-header span { + text-shadow: 1px 1px 2px rgba(0,0,0,0.8); +} + +#chat-toggle { + background: none; + border: none; + color: white; + cursor: pointer; + font-size: 16px; + font-weight: bold; +} + +#chat-body { + height: 350px; + max-height: 50vh; + display: flex; + flex-direction: column; +} + +#chat-messages { + flex-grow: 1; + padding: 10px; + overflow-y: auto; + font-size: 0.9rem; + scrollbar-width: thin; + scrollbar-color: var(--c-accent, #ff00ff) rgba(0,0,0,0.5); + display: flex; + flex-direction: column; + gap: 6px; +} + +#chat-messages::-webkit-scrollbar { + width: 6px; +} + +#chat-messages::-webkit-scrollbar-track { + background: rgba(0,0,0,0.5); +} + +#chat-messages::-webkit-scrollbar-thumb { + background-color: var(--c-accent, #ff00ff); + border-radius: 3px; +} + +.chat-message { + word-break: break-word; + line-height: 1.3; +} + +.chat-ts { + color: #888; + font-size: 0.75rem; + margin-right: 4px; +} + +.chat-nick { + color: var(--c-secondary, #00ffff); + font-weight: bold; + margin-right: 4px; +} + +.chat-text { + color: #eee; +} + +#chat-input-area { + padding: 10px; + border-top: 1px solid rgba(255, 0, 255, 0.3); + background: rgba(0, 0, 0, 0.4); + display: flex; + flex-direction: column; + gap: 5px; +} + +.chat-settings { + display: flex; + gap: 5px; + align-items: center; +} + +.chat-settings input { + flex-grow: 1; + background: rgba(0,0,0,0.6); + border: 1px solid rgba(255,255,255,0.2); + color: #fff; + padding: 4px 6px; + font-size: 0.8rem; + border-radius: 4px; +} + +.chat-settings input:focus { + outline: none; + border-color: var(--c-accent, #ff00ff); +} + +#chat-controls { + display: flex; + gap: 5px; +} + +#chat-input { + flex-grow: 1; + background: rgba(0,0,0,0.6); + border: 1px solid var(--c-accent, #ff00ff); + color: #fff; + padding: 8px; + font-size: 0.9rem; + border-radius: 4px; +} + +#chat-input:focus { + outline: none; + box-shadow: 0 0 5px var(--c-accent, #ff00ff); +} + +#chat-send { + background: var(--c-accent, #ff00ff); + color: white; + border: none; + padding: 0 12px; + border-radius: 4px; + cursor: pointer; + font-weight: bold; + text-transform: uppercase; + font-size: 0.8rem; +} + +#chat-send:active { + transform: scale(0.95); +} + +#chat-status { + text-align: center; + font-size: 0.75rem; + color: #aaa; + margin-top: 2px; +} + +.status-online { color: #0f0 !important; } +.status-offline { color: #f00 !important; } diff --git a/httpserver/data/chat.js b/httpserver/data/chat.js new file mode 100644 index 0000000..502b466 --- /dev/null +++ b/httpserver/data/chat.js @@ -0,0 +1,167 @@ +/* chat.js */ +document.addEventListener('DOMContentLoaded', () => { + const CHAT_WIDGET_HTML = ` + + `; + + document.body.insertAdjacentHTML('beforeend', CHAT_WIDGET_HTML); + + const widget = document.getElementById('chat-widget'); + const header = document.getElementById('chat-header'); + const toggleBtn = document.getElementById('chat-toggle'); + const body = document.getElementById('chat-body'); + const messagesContainer = document.getElementById('chat-messages'); + const input = document.getElementById('chat-input'); + const sendBtn = document.getElementById('chat-send'); + const nickInput = document.getElementById('chat-nick-input'); + const statusEl = document.getElementById('chat-status'); + const statusDot = document.getElementById('chat-status-dot'); + + let ws = null; + let isCollapsed = true; + + // Initialize nickname base (server appends IP suffix) + let savedNick = localStorage.getItem('gw_chat_nick'); + if (!savedNick) { + savedNick = 'visitor'; + localStorage.setItem('gw_chat_nick', savedNick); + } + nickInput.value = savedNick; + + nickInput.addEventListener('change', () => { + let val = nickInput.value.trim(); + if (!val) val = 'visitor'; + nickInput.value = val; + localStorage.setItem('gw_chat_nick', val); + }); + + // Toggle chat + function toggleChat() { + isCollapsed = !isCollapsed; + if (isCollapsed) { + widget.classList.add('collapsed'); + body.style.display = 'none'; + toggleBtn.textContent = '▲'; + } else { + widget.classList.remove('collapsed'); + body.style.display = 'flex'; + toggleBtn.textContent = '▼'; + input.focus(); + scrollToBottom(); + } + } + + header.addEventListener('click', (e) => { + if (e.target !== nickInput && e.target !== input) { + toggleChat(); + } + }); + + function formatTime(ts) { + const d = new Date(ts); + return d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false }); + } + + function appendMessage(msg) { + const div = document.createElement('div'); + div.className = 'chat-message'; + + const tsSpan = document.createElement('span'); + tsSpan.className = 'chat-ts'; + tsSpan.textContent = '[' + formatTime(msg.ts) + ']'; + + const nickSpan = document.createElement('span'); + nickSpan.className = 'chat-nick'; + nickSpan.textContent = msg.nick + ':'; + + const textSpan = document.createElement('span'); + textSpan.className = 'chat-text'; + textSpan.textContent = msg.text; + + div.appendChild(tsSpan); + div.appendChild(nickSpan); + div.appendChild(textSpan); + + messagesContainer.appendChild(div); + scrollToBottom(); + } + + function scrollToBottom() { + messagesContainer.scrollTop = messagesContainer.scrollHeight; + } + + function connect() { + const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; + const host = window.location.host; // includes port if non-standard + ws = new WebSocket(`${protocol}//${host}/chat`); + + ws.onopen = () => { + statusEl.textContent = 'Connected'; + statusDot.className = 'status-online'; + }; + + ws.onmessage = (e) => { + try { + const data = JSON.parse(e.data); + if (data.type === 'history') { + messagesContainer.innerHTML = ''; + data.messages.forEach(appendMessage); + } else { + appendMessage(data); + } + } catch (err) { + console.error('Chat MS error:', err); + } + }; + + ws.onclose = () => { + statusEl.textContent = 'Disconnected. Reconnecting...'; + statusDot.className = 'status-offline'; + setTimeout(connect, 3000); + }; + + ws.onerror = () => { + statusEl.textContent = 'Connection Error'; + ws.close(); + }; + } + + function sendMessage() { + const text = input.value.trim(); + if (!text || ws.readyState !== WebSocket.OPEN) return; + + const nick = nickInput.value.trim() || 'visitor'; + const msg = { nick, text }; + + ws.send(JSON.stringify(msg)); + input.value = ''; + input.focus(); + } + + sendBtn.addEventListener('click', sendMessage); + input.addEventListener('keypress', (e) => { + if (e.key === 'Enter') sendMessage(); + }); + + // Init connection + connect(); +}); diff --git a/httpserver/data/check-status.js b/httpserver/data/check-status.js new file mode 100644 index 0000000..49528e4 --- /dev/null +++ b/httpserver/data/check-status.js @@ -0,0 +1,70 @@ +/** + * check-status.js + * Pings all service URLs and updates services-data.json. + * Then re-embeds the data into services-loader.js so file:// works. + * + * Usage: node check-status.js + */ +const fs = require('fs'); +const path = require('path'); + +const DATA_FILE = path.join(__dirname, 'services-data.json'); +const LOADER_FILE = path.join(__dirname, 'services-loader.js'); +const INLINE_START = '// === INLINE DATA — sync with services-data.json ==='; +const INLINE_END = '// === END INLINE DATA ==='; + +async function checkServices() { + console.log('--- Service Status Check Started ---'); + let data; + try { + data = JSON.parse(fs.readFileSync(DATA_FILE, 'utf8')); + } catch (err) { + console.error('Error reading data file:', err); + return; + } + + for (const service of data.services) { + process.stdout.write(`Checking ${service.name}... `); + try { + const controller = new AbortController(); + const timeout = setTimeout(() => controller.abort(), 5000); + const res = await fetch(service.url, { + signal: controller.signal, + method: 'HEAD', + headers: { 'User-Agent': 'Status-Checker/1.0' } + }); + clearTimeout(timeout); + if (res.status === 200 || res.status === 201) { + console.log('\x1b[32mUP\x1b[0m (' + res.status + ')'); + delete service.status; + } else { + console.log('\x1b[33mDOWN\x1b[0m (' + res.status + ')'); + service.status = 'maintenance'; + } + } catch (err) { + console.log('\x1b[31mOFFLINE\x1b[0m (' + err.message + ')'); + service.status = 'maintenance'; + } + } + + // Write updated services-data.json + fs.writeFileSync(DATA_FILE, JSON.stringify(data, null, 2), 'utf8'); + console.log('\n✓ services-data.json updated\n'); + + // Sync embedded data into services-loader.js + let loader = fs.readFileSync(LOADER_FILE, 'utf8'); + const startIdx = loader.indexOf(INLINE_START); + const endIdx = loader.indexOf(INLINE_END); + if (startIdx === -1 || endIdx === -1) { + console.error('Could not find INLINE DATA markers in services-loader.js'); + return; + } + const before = loader.substring(0, startIdx); + const after = loader.substring(endIdx + INLINE_END.length); + const newLine = `${INLINE_START}\nconst SERVICES_EMBEDDED = ${JSON.stringify(data)};\n${INLINE_END}`; + fs.writeFileSync(LOADER_FILE, before + newLine + after, 'utf8'); + console.log('✓ services-loader.js inline data synced'); + console.log('--- Done ---'); +} + +checkServices(); diff --git a/httpserver/data/ddate-now b/httpserver/data/ddate-now new file mode 100644 index 0000000..f22057b --- /dev/null +++ b/httpserver/data/ddate-now @@ -0,0 +1,2 @@ +Today is Pungenday, the 5th day of Discord in the YOLD 3192 +Celebrate Mojoday diff --git a/httpserver/data/gs.html b/httpserver/data/gs.html new file mode 100644 index 0000000..d606657 --- /dev/null +++ b/httpserver/data/gs.html @@ -0,0 +1,272 @@ + + + + + + + GalaxySpin.Space + + + + + +
+
+ +
+
+

GalaxySpin.Space

+

Welcome to the experience!

+ +
+
+ ▶ Notice to all users: temporal fluctuations may occur during extended usage. Please report any + space time distortions or temporal paradoxes to administrators immediately. ◀ +
+
+ + + +

+ brought to you by GravityWell Services +

+
+ + +
+ + + + + + diff --git a/httpserver/data/gw.css b/httpserver/data/gw.css new file mode 100755 index 0000000..08e8105 --- /dev/null +++ b/httpserver/data/gw.css @@ -0,0 +1,642 @@ +:root { + --c-bg: #000; + --c-bg-alt: #171717; + --c-bg-dim: rgba(23, 23, 23, 0.5); + --c-border: #262626; + --c-border-mid: #404040; + --c-border-light: #525252; + --c-text: #e5e5e5; + --c-text-dim: #d4d4d4; + --c-text-muted: #a3a3a3; + --c-text-faded: #737373; + --c-white: #fff; + --c-accent: #0a7; + --c-red: #ef4444; + --c-red-dark: #dc2626; + --c-red-bg: #7f1d1d; + --c-gold: #ca8a04; + --c-yellow: #eab308; + --c-blue: #60a5fa; + --c-blue-light: #93c5fd; + --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; +} + +* { + margin: 0; + padding: 0; + box-sizing: border-box +} + +html { + scroll-behavior: smooth +} + +body { + background: var(--c-bg); + color: var(--c-text); + font-family: var(--font-mono); + min-height: 100vh +} + +::selection { + background: var(--c-white); + color: var(--c-bg) +} + +a { + color: inherit; + text-decoration: none +} + +ul { + list-style: none +} + +li+li { + margin-top: .5rem +} + +::-webkit-scrollbar { + width: 12px +} + +::-webkit-scrollbar-track { + background: var(--c-bg); + border-left: 1px solid #333 +} + +::-webkit-scrollbar-thumb { + background: var(--c-white); + border: 2px solid var(--c-bg) +} + +::-webkit-scrollbar-thumb:hover { + background: #ccc +} + +#warp { + position: fixed; + top: 0; + left: 0; + z-index: -1; + display: none +} + +#warp.active { + display: block +} + +.warp-trigger { + cursor: pointer; + text-decoration: underline dotted +} + +.warp-trigger:hover { + color: var(--c-accent) +} + +.container { + max-width: 42rem; + margin: 0 auto; + border-left: 1px solid var(--c-border); + border-right: 1px solid var(--c-border); + min-height: 100vh; + background: var(--c-bg); + box-shadow: 0 0 50px rgba(255, 255, 255, .05) +} + +header { + padding: 1rem; + border-bottom: 2px solid var(--c-white); + background: var(--c-bg-alt) +} + +h1 { + font-size: 1.875rem; + font-weight: 700; + letter-spacing: -.05em; + color: var(--c-white); + margin-bottom: .5rem +} + +h1 .subdomain { + color: var(--c-text-faded) +} + +.header-text { + border-left: 4px solid var(--c-border-light); + padding-left: 1rem; + font-size: .875rem; + line-height: 1.25 +} + +.header-text p:first-child { + color: var(--c-text-dim) +} + +.header-text p:last-child { + color: var(--c-text-faded) +} + +nav { + position: sticky; + top: 0; + z-index: 40; + background: var(--c-bg); + border-bottom: 1px solid var(--c-border); + overflow-x: auto +} + +nav ul { + display: flex; + white-space: nowrap +} + +nav li { + flex: 1; + text-align: center +} + +nav a { + display: block; + padding: .5rem .75rem; + font-size: .875rem; + font-weight: 700; + border-right: 1px solid var(--c-bg-alt) +} + +nav a:hover, +.service-name:hover, +.extension-link:hover, +.donate-link:hover, +.contact-item a:hover, +.contact-item span:hover { + background: var(--c-white); + color: var(--c-bg) +} + +main { + padding: .75rem 1.25rem +} + +section { + margin-bottom: 2rem; + scroll-margin-top: 5rem +} + +p { + margin-bottom: .75rem; + color: var(--c-text-dim) +} + +h2 { + font-size: 1.25rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: .1em; + margin-bottom: 1rem; + display: inline-block; + border-bottom: 2px solid var(--c-white); + padding-bottom: .25rem +} + +h3 { + font-size: .75rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: .2em; + margin-bottom: .5rem; + color: var(--c-text-faded); + border-bottom: 1px solid var(--c-border); + padding-bottom: .5rem; + transition: color .2s +} + +.group:hover h3 { + color: var(--c-white) +} + +#ddate { + font-size: .75rem; + color: var(--c-text-faded); + text-transform: uppercase; + letter-spacing: .1em; + border-bottom: 1px solid var(--c-bg-alt); + padding-bottom: .5rem; + margin-bottom: 2rem +} + +.grid { + display: grid; + gap: 1.5rem +} + +.services-section-title { + grid-column: 1 / -1; + margin-bottom: 0; + border-bottom: 1px solid var(--c-border); + padding-bottom: .5rem +} + +.services-section-title .hosts-note { + font-size: .85em; + font-weight: 400; + color: var(--c-text-faded) +} + +.services-archived { + grid-column: 1 / -1 +} + +.services-archived .archived-summary { + text-transform: uppercase; + letter-spacing: .05em; + color: var(--c-text-faded) +} + +.services-archived .archived-grid { + margin-top: .75rem +} + +.services-intro { + color: var(--c-text-muted); + font-size: .9rem; + margin-bottom: 1rem +} + +.group.archived-group h3 { + color: var(--c-text-faded) +} + +details { + border: 1px solid var(--c-border-mid); + background: var(--c-bg-dim); + margin-top: 1.5rem; + transition: all .2s +} + +details[open] { + background: var(--c-bg-alt); + border-color: var(--c-white) +} + +details[open] summary { + border-bottom: 1px solid var(--c-border-mid) +} + +summary { + cursor: pointer; + padding: .75rem; + font-weight: 700; + user-select: none; + display: flex; + justify-content: space-between; + align-items: center +} + +summary:hover { + background: var(--c-border); + color: var(--c-white) +} + +details .content { + padding: .75rem +} + +details .content p { + color: var(--c-text-muted); + margin-bottom: .75rem +} + +.link-item { + display: flex; + align-items: center; + color: var(--c-text-dim) +} + +.link-item:hover { + color: var(--c-white); + text-decoration: underline; + text-decoration-thickness: 2px; + text-underline-offset: 4px +} + +.link-icon { + width: 1rem; + height: 1rem; + margin-right: .5rem; + display: inline-flex; + align-items: center; + justify-content: center; + font-size: 10px; + background: var(--c-border); + border: 1px solid var(--c-border-light) +} + +.extension-link, +.donate-link { + display: block; + padding: .75rem; + border: 1px solid var(--c-border-mid); + transition: all .2s; + text-align: center; + font-weight: 700; + font-size: .875rem +} + +.extension-link { + padding: .5rem +} + +.donate-link { + border-color: var(--c-border) +} + +.extension-link:hover, +.donate-link:hover { + border-color: var(--c-white) +} + +.contact-item { + word-break: break-all; + font-size: .875rem +} + +.contact-label { + display: block; + color: var(--c-text-faded); + font-size: .75rem; + text-transform: uppercase; + margin-bottom: .25rem +} + +.service-link { + display: flex; + flex-wrap: wrap; + align-items: baseline; + gap: .5rem +} + +.service-name { + font-weight: 700; + font-size: 1.125rem; + padding: 0 .25rem; + margin-left: -.25rem +} + +.service-meta { + font-size: .75rem; + color: var(--c-text-faded) +} + +.service-meta a { + text-decoration: underline dotted +} + +.service-meta a:hover { + color: var(--c-white) +} + +/* Maintenance Status */ +.status-maintenance { + opacity: 0.5; + filter: grayscale(1); + pointer-events: none; +} + +/* Back-compat: treat "down" the same as prior "maintenance" */ +.status-down { + opacity: 0.5; + filter: grayscale(1); + pointer-events: none; +} + +.status-maintenance a { + cursor: not-allowed; + text-decoration: line-through !important; +} + +.status-down a { + cursor: not-allowed; + text-decoration: line-through !important; +} + +.maintenance-badge { + font-size: 0.65rem; + letter-spacing: 0.05em; + color: var(--c-red); + margin-left: 0.5rem; + vertical-align: middle; +} + +.guest-info { + margin-bottom: 1.5rem; + border: 1px solid var(--c-border-mid); + background: rgba(23, 23, 23, .3) +} + +.guest-info summary { + padding: .75rem; + font-size: .875rem; + color: var(--c-yellow); + text-transform: uppercase; + letter-spacing: .05em +} + +.guest-info .content { + border-top: 1px solid var(--c-border-mid); + font-size: .875rem +} + +.guest-credentials { + background: var(--c-bg-alt); + padding: .75rem; + border-left: 4px solid var(--c-white); + font-size: .75rem +} + +.guest-credentials p { + margin: 0 +} + +.guest-credentials .label, +.guest-note { + color: var(--c-text-faded) +} + +.guest-note { + font-size: .75rem +} + +.crypto-details { + border-color: var(--c-border); + background: transparent +} + +.crypto-details summary { + text-transform: uppercase; + letter-spacing: .1em; + font-size: .875rem; + border: 1px solid var(--c-border) +} + +.crypto-details summary span:last-child { + transition: transform .2s +} + +.crypto-details[open] summary { + background: var(--c-white); + color: var(--c-bg); + border-color: var(--c-white) +} + +.crypto-details[open] summary span:last-child { + transform: rotate(180deg) +} + +.crypto-content { + margin-top: .5rem; + background: var(--c-bg); + border: 1px solid var(--c-border); + padding: 1rem; + position: relative +} + +.crypto-corner { + position: absolute; + top: 0; + right: 0; + width: .5rem; + height: .5rem; + background: var(--c-white) +} + +.crypto-item { + margin-bottom: 1rem +} + +.crypto-header { + display: flex; + justify-content: space-between; + align-items: baseline; + border-bottom: 1px solid var(--c-border); + padding-bottom: .25rem; + margin-bottom: .5rem +} + +.crypto-name { + font-weight: 700; + color: var(--c-gold) +} + +.crypto-label { + font-size: 10px; + color: var(--c-border-light) +} + +.crypto-address { + display: block; + font-size: .75rem; + word-break: break-all; + color: var(--c-text-muted); + user-select: all; + background: var(--c-bg-dim); + padding: .5rem; + border-left: 2px solid var(--c-border) +} + +.qr-container { + width: 100%; + height: 8rem; + border: 1px solid var(--c-border); + display: flex; + align-items: center; + justify-content: center; + background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0IiBoZWlnaHQ9IjQiPgo8cmVjdCB3aWR0aD0iNCIgaGVpZ2h0PSI0IiBmaWxsPSIjMTExIiAvPgo8L3N2Zz4='); + margin-top: .5rem +} + +.qr-placeholder { + background: var(--c-bg); + padding: .5rem; + font-size: 10px; + border: 1px solid var(--c-border); + color: var(--c-text-faded) +} + +.footer-links { + padding-top: 1.5rem; + border-top: 1px solid var(--c-border) +} + +.footer-links h2 { + text-align: center; + color: var(--c-text-faded); + font-size: .875rem; + margin-bottom: 1.5rem +} + +.link-grid { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: .5rem +} + +.footer-link { + padding: .25rem .75rem; + font-size: .75rem; + border: 1px solid var(--c-border); + text-transform: uppercase; + font-weight: 700; + transition: transform .2s; + color: var(--c-text-faded) +} + +.footer-link:hover { + border-color: var(--c-white); + color: var(--c-white); + background: var(--c-bg-alt); + transform: translateY(-.25rem) +} + +.footer-link.danger { + border-color: var(--c-red-bg); + color: var(--c-red) +} + +.footer-link.danger:hover { + background: var(--c-red-dark); + color: var(--c-white) +} + +footer { + padding: 1rem; + border-top: 1px solid var(--c-border); + text-align: center; + font-size: .75rem; + color: var(--c-border-light) +} + +@media(min-width:768px) { + h1 { + font-size: 3rem + } + + .header-text { + font-size: 1rem + } + + main { + padding: 1rem 1.25rem + } + + .grid { + grid-template-columns: repeat(2, 1fr) + } + + .grid.services { + column-gap: 2rem; + row-gap: 1.5rem + } +} \ No newline at end of file diff --git a/httpserver/data/gw.html b/httpserver/data/gw.html new file mode 100644 index 0000000..01ea69a --- /dev/null +++ b/httpserver/data/gw.html @@ -0,0 +1,229 @@ + + + + + + + GravityWell.xYz + + + + + + + + +
+
+

GRAVITYWELL.xYz

+
+

Self-Hosting is killing corporate profits!

+

We left these services open so you can help.

+
+
+ + + +
+
Loading date...
+ +
+

About This Space

+

An experiment in self-hosting, data archiving, and community building.

+

Most services here are open to new users and connected with the Fediverse. All services are running on home + infrastructure and a cheap VPS.

+

Self-hosting is the practice of hosting and managing applications on your own server(s) + instead of consuming from + + SaaSS providers.

+ +
+ [+] TRY THESE BANNED EXTENSIONS +
+

The following browser extensions have been known to cause problems for surveillance capitalism and as + such have been banned by Google, but you can still use them!

+ +
+
+
+ +
+
+

Community

+ +
+ +
+

Contact

+ +
+
+ +
+

Services

+ +
+ [!] Read: Guest Access Info +
+

Some services don't have a sign-up option. Use the guest account to try them out.

+
+

USER: gwguest

+

PASS: gravitywell.xyz

+
+

* GravityWell.xYz services hosted on home server.
* ugh.im services hosted on VPS. +

+
+
+ +
+ +
+
+ + + + +
+ +
+

GRAVITYWELL.XYZ | Retro

+
+
+ + + + + + + + \ No newline at end of file diff --git a/httpserver/data/index.html b/httpserver/data/index.html new file mode 100644 index 0000000..2089bf5 --- /dev/null +++ b/httpserver/data/index.html @@ -0,0 +1,12 @@ + + + + + + GravityWell.xYz + + + +

Go to GravityWell.xYz

+ + diff --git a/httpserver/data/intro.opus b/httpserver/data/intro.opus new file mode 100644 index 0000000..d023558 Binary files /dev/null and b/httpserver/data/intro.opus differ diff --git a/httpserver/data/main.js b/httpserver/data/main.js new file mode 100755 index 0000000..48427c6 --- /dev/null +++ b/httpserver/data/main.js @@ -0,0 +1,91 @@ +fetch('./ddate-now') + .then(r => r.text()) + .then(d => { document.getElementById('ddate').textContent = d.trim(); }) + .catch(() => { document.getElementById('ddate').textContent = ''; }); + +const canvas = document.getElementById('warp'); +const ctx = canvas.getContext('2d'); +let w, h, cx, cy, stars = [], animId = null, active = false; +const prefersReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches; +const isMobile = window.innerWidth < 768 || window.innerHeight < 600 || /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent); +const starCount = isMobile ? 200 : 400; +const speed = prefersReduced ? 0.01 : 0.02; + +function resize() { + w = canvas.width = window.innerWidth; + h = canvas.height = window.innerHeight; + cx = w / 2; + cy = h / 2; +} + +class Star { + constructor() { this.reset(); } + reset() { + const angle = Math.random() * Math.PI * 2; + const radius = Math.random() * Math.max(w, h); + this.x = Math.cos(angle) * radius; + this.y = Math.sin(angle) * radius; + this.z = Math.random() * w; + this.pz = this.z; + } + update() { + this.pz = this.z; + this.z -= speed * this.z; + if (this.z < 1) this.reset(); + } + draw() { + const sz = 1 / this.z, spz = 1 / this.pz; + const sx = this.x * sz * w + cx, sy = this.y * sz * h + cy; + const px = this.x * spz * w + cx, py = this.y * spz * h + cy; + const r = Math.max(0, (1 - this.z / w) * 2); + ctx.beginPath(); + ctx.strokeStyle = `rgba(255, 255, 255, ${r})`; + ctx.lineWidth = r * 2; + ctx.moveTo(px, py); + ctx.lineTo(sx, sy); + ctx.stroke(); + } +} + +function init() { + resize(); + stars = []; + for (let i = 0; i < starCount; i++) stars.push(new Star()); +} + +function animate() { + ctx.fillStyle = 'rgba(0, 0, 0, 0.2)'; + ctx.fillRect(0, 0, w, h); + for (let i = 0; i < stars.length; i++) { + stars[i].update(); + stars[i].draw(); + } + animId = requestAnimationFrame(animate); +} + +function startWarp() { + if (active) return; + active = true; + canvas.classList.add('active'); + init(); + animate(); +} + +function stopWarp() { + if (!active) return; + active = false; + canvas.classList.remove('active'); + if (animId) cancelAnimationFrame(animId); +} + +document.addEventListener('click', (e) => { + if (e.target.classList.contains('warp-trigger')) { + e.preventDefault(); + active ? stopWarp() : startWarp(); + } +}); + +window.addEventListener('resize', () => { + if (active) resize(); +}); + diff --git a/httpserver/data/mew-neocities/README-neocities.md b/httpserver/data/mew-neocities/README-neocities.md new file mode 100644 index 0000000..2145cc4 --- /dev/null +++ b/httpserver/data/mew-neocities/README-neocities.md @@ -0,0 +1,26 @@ +## Mew Timeline — Neocities Version + +This folder is a static copy of the original `mew` timeline site, prepared for hosting on Neocities. + +### How to deploy + +1. **Create the site on Neocities** + - Log in to Neocities and create (or open) the site you want to use. + +2. **Upload files** + - Upload `index.html` to the root of your Neocities site (or to a subfolder if you want the timeline at a path like `/mew/`). + - Create a `library/` folder on Neocities. + - Upload all of the media files listed in the `MEDIA` array inside `index.html` into that `library/` folder. + +3. **Paths / structure** + - The page expects files at `./library/` relative to `index.html`. + - If you keep that structure, you do **not** need to change any code. + +4. **Using a subdirectory (optional)** + - If you put `index.html` into a folder such as `/mew/`, also put the `library/` folder inside that same folder. + - For example: + - `/mew/index.html` + - `/mew/library/2013-10-04_11-32-51.webp` + +Once the files are uploaded, visit your Neocities URL and the slideshow + timeline should work entirely client‑side. + diff --git a/httpserver/data/mew-neocities/bg.png b/httpserver/data/mew-neocities/bg.png new file mode 100644 index 0000000..a63785a Binary files /dev/null and b/httpserver/data/mew-neocities/bg.png differ diff --git a/httpserver/data/mew-neocities/index.html b/httpserver/data/mew-neocities/index.html new file mode 100644 index 0000000..a380b9e --- /dev/null +++ b/httpserver/data/mew-neocities/index.html @@ -0,0 +1,450 @@ + + + + + + + Timeline of Mew + + + + + +
+

Timeline of Mew

+

Brightest Smile, Bestest Buddy (2013—2026)

+
+ +
+ Mew +
+ +
+
+ + + + + + + + + \ No newline at end of file diff --git a/httpserver/data/mew-neocities/library/2013-10-04_11-32-51.jpg b/httpserver/data/mew-neocities/library/2013-10-04_11-32-51.jpg new file mode 100644 index 0000000..6f6ae77 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2013-10-04_11-32-51.jpg differ diff --git a/httpserver/data/mew-neocities/library/2013-10-04_11-34-12.jpg b/httpserver/data/mew-neocities/library/2013-10-04_11-34-12.jpg new file mode 100644 index 0000000..3c3aa9c Binary files /dev/null and b/httpserver/data/mew-neocities/library/2013-10-04_11-34-12.jpg differ diff --git a/httpserver/data/mew-neocities/library/2013-10-04_11-44-25.jpg b/httpserver/data/mew-neocities/library/2013-10-04_11-44-25.jpg new file mode 100644 index 0000000..67a46ce Binary files /dev/null and b/httpserver/data/mew-neocities/library/2013-10-04_11-44-25.jpg differ diff --git a/httpserver/data/mew-neocities/library/2013-10-04_11-54-42.jpg b/httpserver/data/mew-neocities/library/2013-10-04_11-54-42.jpg new file mode 100644 index 0000000..975ed6e Binary files /dev/null and b/httpserver/data/mew-neocities/library/2013-10-04_11-54-42.jpg differ diff --git a/httpserver/data/mew-neocities/library/2013-10-04_21-36-05.jpg b/httpserver/data/mew-neocities/library/2013-10-04_21-36-05.jpg new file mode 100644 index 0000000..820ab3c Binary files /dev/null and b/httpserver/data/mew-neocities/library/2013-10-04_21-36-05.jpg differ diff --git a/httpserver/data/mew-neocities/library/2013-10-05_01-04-33.jpg b/httpserver/data/mew-neocities/library/2013-10-05_01-04-33.jpg new file mode 100644 index 0000000..6ec752b Binary files /dev/null and b/httpserver/data/mew-neocities/library/2013-10-05_01-04-33.jpg differ diff --git a/httpserver/data/mew-neocities/library/2013-10-05_01-05-44.jpg b/httpserver/data/mew-neocities/library/2013-10-05_01-05-44.jpg new file mode 100644 index 0000000..1f721d3 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2013-10-05_01-05-44.jpg differ diff --git a/httpserver/data/mew-neocities/library/2013-10-05_01-07-04.jpg b/httpserver/data/mew-neocities/library/2013-10-05_01-07-04.jpg new file mode 100644 index 0000000..c947810 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2013-10-05_01-07-04.jpg differ diff --git a/httpserver/data/mew-neocities/library/2013-10-05_18-16-39.jpg b/httpserver/data/mew-neocities/library/2013-10-05_18-16-39.jpg new file mode 100644 index 0000000..637ec5b Binary files /dev/null and b/httpserver/data/mew-neocities/library/2013-10-05_18-16-39.jpg differ diff --git a/httpserver/data/mew-neocities/library/2013-10-06_12-39-45.jpg b/httpserver/data/mew-neocities/library/2013-10-06_12-39-45.jpg new file mode 100644 index 0000000..3ec5f36 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2013-10-06_12-39-45.jpg differ diff --git a/httpserver/data/mew-neocities/library/2013-10-06_16-51-58.jpg b/httpserver/data/mew-neocities/library/2013-10-06_16-51-58.jpg new file mode 100644 index 0000000..d3ccba9 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2013-10-06_16-51-58.jpg differ diff --git a/httpserver/data/mew-neocities/library/2013-10-08_14-03-20.jpg b/httpserver/data/mew-neocities/library/2013-10-08_14-03-20.jpg new file mode 100644 index 0000000..b1537e8 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2013-10-08_14-03-20.jpg differ diff --git a/httpserver/data/mew-neocities/library/2013-10-08_14-03-32.jpg b/httpserver/data/mew-neocities/library/2013-10-08_14-03-32.jpg new file mode 100644 index 0000000..492141f Binary files /dev/null and b/httpserver/data/mew-neocities/library/2013-10-08_14-03-32.jpg differ diff --git a/httpserver/data/mew-neocities/library/2013-10-08_14-50-05.jpg b/httpserver/data/mew-neocities/library/2013-10-08_14-50-05.jpg new file mode 100644 index 0000000..f34bace Binary files /dev/null and b/httpserver/data/mew-neocities/library/2013-10-08_14-50-05.jpg differ diff --git a/httpserver/data/mew-neocities/library/2013-10-13_13-48-50.jpg b/httpserver/data/mew-neocities/library/2013-10-13_13-48-50.jpg new file mode 100644 index 0000000..66bad45 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2013-10-13_13-48-50.jpg differ diff --git a/httpserver/data/mew-neocities/library/2013-11-10_04-22-11.jpg b/httpserver/data/mew-neocities/library/2013-11-10_04-22-11.jpg new file mode 100644 index 0000000..d47e322 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2013-11-10_04-22-11.jpg differ diff --git a/httpserver/data/mew-neocities/library/2013-11-16_04-43-24.jpg b/httpserver/data/mew-neocities/library/2013-11-16_04-43-24.jpg new file mode 100644 index 0000000..e7ef115 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2013-11-16_04-43-24.jpg differ diff --git a/httpserver/data/mew-neocities/library/2013-11-16_04-43-56.jpg b/httpserver/data/mew-neocities/library/2013-11-16_04-43-56.jpg new file mode 100644 index 0000000..c4dc78e Binary files /dev/null and b/httpserver/data/mew-neocities/library/2013-11-16_04-43-56.jpg differ diff --git a/httpserver/data/mew-neocities/library/2013-11-16_04-45-41.jpg b/httpserver/data/mew-neocities/library/2013-11-16_04-45-41.jpg new file mode 100644 index 0000000..fef20d4 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2013-11-16_04-45-41.jpg differ diff --git a/httpserver/data/mew-neocities/library/2013-11-16_04-49-32.jpg b/httpserver/data/mew-neocities/library/2013-11-16_04-49-32.jpg new file mode 100644 index 0000000..efde135 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2013-11-16_04-49-32.jpg differ diff --git a/httpserver/data/mew-neocities/library/2013-11-16_04-50-16.jpg b/httpserver/data/mew-neocities/library/2013-11-16_04-50-16.jpg new file mode 100644 index 0000000..e527389 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2013-11-16_04-50-16.jpg differ diff --git a/httpserver/data/mew-neocities/library/2013-11-20_10-03-56.jpg b/httpserver/data/mew-neocities/library/2013-11-20_10-03-56.jpg new file mode 100644 index 0000000..3a961d4 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2013-11-20_10-03-56.jpg differ diff --git a/httpserver/data/mew-neocities/library/2013-11-20_10-04-22.jpg b/httpserver/data/mew-neocities/library/2013-11-20_10-04-22.jpg new file mode 100644 index 0000000..418a5e2 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2013-11-20_10-04-22.jpg differ diff --git a/httpserver/data/mew-neocities/library/2013-11-23_21-07-53.jpg b/httpserver/data/mew-neocities/library/2013-11-23_21-07-53.jpg new file mode 100644 index 0000000..c542277 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2013-11-23_21-07-53.jpg differ diff --git a/httpserver/data/mew-neocities/library/2013-12-24_09-52-36.jpg b/httpserver/data/mew-neocities/library/2013-12-24_09-52-36.jpg new file mode 100644 index 0000000..d97076c Binary files /dev/null and b/httpserver/data/mew-neocities/library/2013-12-24_09-52-36.jpg differ diff --git a/httpserver/data/mew-neocities/library/2014-01-14_23-46-24.jpg b/httpserver/data/mew-neocities/library/2014-01-14_23-46-24.jpg new file mode 100644 index 0000000..6894b6d Binary files /dev/null and b/httpserver/data/mew-neocities/library/2014-01-14_23-46-24.jpg differ diff --git a/httpserver/data/mew-neocities/library/2014-01-15_13-59-21.jpg b/httpserver/data/mew-neocities/library/2014-01-15_13-59-21.jpg new file mode 100644 index 0000000..5e4dcf7 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2014-01-15_13-59-21.jpg differ diff --git a/httpserver/data/mew-neocities/library/2014-10-05_17-27-34.jpg b/httpserver/data/mew-neocities/library/2014-10-05_17-27-34.jpg new file mode 100644 index 0000000..36006cf Binary files /dev/null and b/httpserver/data/mew-neocities/library/2014-10-05_17-27-34.jpg differ diff --git a/httpserver/data/mew-neocities/library/2014-12-04_18-18-14.jpg b/httpserver/data/mew-neocities/library/2014-12-04_18-18-14.jpg new file mode 100644 index 0000000..9ebc727 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2014-12-04_18-18-14.jpg differ diff --git a/httpserver/data/mew-neocities/library/2015-08-23_19-05-48.jpg b/httpserver/data/mew-neocities/library/2015-08-23_19-05-48.jpg new file mode 100644 index 0000000..439a62e Binary files /dev/null and b/httpserver/data/mew-neocities/library/2015-08-23_19-05-48.jpg differ diff --git a/httpserver/data/mew-neocities/library/2015-09-19_03-39-04.jpg b/httpserver/data/mew-neocities/library/2015-09-19_03-39-04.jpg new file mode 100644 index 0000000..85c340e Binary files /dev/null and b/httpserver/data/mew-neocities/library/2015-09-19_03-39-04.jpg differ diff --git a/httpserver/data/mew-neocities/library/2015-12-24_11-28-52.jpg b/httpserver/data/mew-neocities/library/2015-12-24_11-28-52.jpg new file mode 100644 index 0000000..dceb32a Binary files /dev/null and b/httpserver/data/mew-neocities/library/2015-12-24_11-28-52.jpg differ diff --git a/httpserver/data/mew-neocities/library/2016-08-13_16-40-49.jpg b/httpserver/data/mew-neocities/library/2016-08-13_16-40-49.jpg new file mode 100644 index 0000000..b1d9b31 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2016-08-13_16-40-49.jpg differ diff --git a/httpserver/data/mew-neocities/library/2016-08-29_22-02-56.jpg b/httpserver/data/mew-neocities/library/2016-08-29_22-02-56.jpg new file mode 100644 index 0000000..b89b05d Binary files /dev/null and b/httpserver/data/mew-neocities/library/2016-08-29_22-02-56.jpg differ diff --git a/httpserver/data/mew-neocities/library/2016-09-08_21-14-59.jpg b/httpserver/data/mew-neocities/library/2016-09-08_21-14-59.jpg new file mode 100644 index 0000000..ff21079 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2016-09-08_21-14-59.jpg differ diff --git a/httpserver/data/mew-neocities/library/2016-10-23_23-10-23.jpg b/httpserver/data/mew-neocities/library/2016-10-23_23-10-23.jpg new file mode 100644 index 0000000..5c02200 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2016-10-23_23-10-23.jpg differ diff --git a/httpserver/data/mew-neocities/library/2016-10-23_23-34-19.jpg b/httpserver/data/mew-neocities/library/2016-10-23_23-34-19.jpg new file mode 100644 index 0000000..efc3f29 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2016-10-23_23-34-19.jpg differ diff --git a/httpserver/data/mew-neocities/library/2016-12-09_10-02-08.jpg b/httpserver/data/mew-neocities/library/2016-12-09_10-02-08.jpg new file mode 100644 index 0000000..d199a7d Binary files /dev/null and b/httpserver/data/mew-neocities/library/2016-12-09_10-02-08.jpg differ diff --git a/httpserver/data/mew-neocities/library/2016-12-10_21-58-17.jpg b/httpserver/data/mew-neocities/library/2016-12-10_21-58-17.jpg new file mode 100644 index 0000000..4757814 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2016-12-10_21-58-17.jpg differ diff --git a/httpserver/data/mew-neocities/library/2016-12-10_21-58-22.jpg b/httpserver/data/mew-neocities/library/2016-12-10_21-58-22.jpg new file mode 100644 index 0000000..85626c8 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2016-12-10_21-58-22.jpg differ diff --git a/httpserver/data/mew-neocities/library/2016-12-10_21-58-33.jpg b/httpserver/data/mew-neocities/library/2016-12-10_21-58-33.jpg new file mode 100644 index 0000000..cf5aa3f Binary files /dev/null and b/httpserver/data/mew-neocities/library/2016-12-10_21-58-33.jpg differ diff --git a/httpserver/data/mew-neocities/library/2016-12-10_22-40-32.jpg b/httpserver/data/mew-neocities/library/2016-12-10_22-40-32.jpg new file mode 100644 index 0000000..27fb48c Binary files /dev/null and b/httpserver/data/mew-neocities/library/2016-12-10_22-40-32.jpg differ diff --git a/httpserver/data/mew-neocities/library/2016-12-11_06-03-13.jpg b/httpserver/data/mew-neocities/library/2016-12-11_06-03-13.jpg new file mode 100644 index 0000000..a9c9090 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2016-12-11_06-03-13.jpg differ diff --git a/httpserver/data/mew-neocities/library/2016-12-17_22-42-58.gif b/httpserver/data/mew-neocities/library/2016-12-17_22-42-58.gif new file mode 100644 index 0000000..502924a Binary files /dev/null and b/httpserver/data/mew-neocities/library/2016-12-17_22-42-58.gif differ diff --git a/httpserver/data/mew-neocities/library/2016-12-18_21-03-31.jpg b/httpserver/data/mew-neocities/library/2016-12-18_21-03-31.jpg new file mode 100644 index 0000000..d0af8cd Binary files /dev/null and b/httpserver/data/mew-neocities/library/2016-12-18_21-03-31.jpg differ diff --git a/httpserver/data/mew-neocities/library/2017-03-08_08-52-13.jpg b/httpserver/data/mew-neocities/library/2017-03-08_08-52-13.jpg new file mode 100644 index 0000000..57049f8 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2017-03-08_08-52-13.jpg differ diff --git a/httpserver/data/mew-neocities/library/2017-03-15_16-14-27.jpg b/httpserver/data/mew-neocities/library/2017-03-15_16-14-27.jpg new file mode 100644 index 0000000..8ac1e95 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2017-03-15_16-14-27.jpg differ diff --git a/httpserver/data/mew-neocities/library/2017-03-31_17-20-19.jpg b/httpserver/data/mew-neocities/library/2017-03-31_17-20-19.jpg new file mode 100644 index 0000000..d33ce3e Binary files /dev/null and b/httpserver/data/mew-neocities/library/2017-03-31_17-20-19.jpg differ diff --git a/httpserver/data/mew-neocities/library/2017-04-01_00-14-00.gif b/httpserver/data/mew-neocities/library/2017-04-01_00-14-00.gif new file mode 100644 index 0000000..f9c8cee Binary files /dev/null and b/httpserver/data/mew-neocities/library/2017-04-01_00-14-00.gif differ diff --git a/httpserver/data/mew-neocities/library/2017-04-19_01-50-02.jpg b/httpserver/data/mew-neocities/library/2017-04-19_01-50-02.jpg new file mode 100644 index 0000000..4295673 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2017-04-19_01-50-02.jpg differ diff --git a/httpserver/data/mew-neocities/library/2017-06-14_09-51-56.jpg b/httpserver/data/mew-neocities/library/2017-06-14_09-51-56.jpg new file mode 100644 index 0000000..b6d8035 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2017-06-14_09-51-56.jpg differ diff --git a/httpserver/data/mew-neocities/library/2018-01-21_18-02-00.jpg b/httpserver/data/mew-neocities/library/2018-01-21_18-02-00.jpg new file mode 100644 index 0000000..936eb88 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2018-01-21_18-02-00.jpg differ diff --git a/httpserver/data/mew-neocities/library/2018-01-21_18-04-03.jpg b/httpserver/data/mew-neocities/library/2018-01-21_18-04-03.jpg new file mode 100644 index 0000000..950fc2a Binary files /dev/null and b/httpserver/data/mew-neocities/library/2018-01-21_18-04-03.jpg differ diff --git a/httpserver/data/mew-neocities/library/2018-01-21_18-23-41_2.jpg b/httpserver/data/mew-neocities/library/2018-01-21_18-23-41_2.jpg new file mode 100644 index 0000000..64e5526 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2018-01-21_18-23-41_2.jpg differ diff --git a/httpserver/data/mew-neocities/library/2018-01-22_02-26-40.jpg b/httpserver/data/mew-neocities/library/2018-01-22_02-26-40.jpg new file mode 100644 index 0000000..c59df12 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2018-01-22_02-26-40.jpg differ diff --git a/httpserver/data/mew-neocities/library/2018-01-22_10-15-08.jpg b/httpserver/data/mew-neocities/library/2018-01-22_10-15-08.jpg new file mode 100644 index 0000000..65da9f7 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2018-01-22_10-15-08.jpg differ diff --git a/httpserver/data/mew-neocities/library/2018-03-22_12-42-32.jpg b/httpserver/data/mew-neocities/library/2018-03-22_12-42-32.jpg new file mode 100644 index 0000000..ed3f752 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2018-03-22_12-42-32.jpg differ diff --git a/httpserver/data/mew-neocities/library/2018-06-17_00-26-43.jpg b/httpserver/data/mew-neocities/library/2018-06-17_00-26-43.jpg new file mode 100644 index 0000000..d41ae6b Binary files /dev/null and b/httpserver/data/mew-neocities/library/2018-06-17_00-26-43.jpg differ diff --git a/httpserver/data/mew-neocities/library/2018-06-19_06-20-25.gif b/httpserver/data/mew-neocities/library/2018-06-19_06-20-25.gif new file mode 100644 index 0000000..16c47c8 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2018-06-19_06-20-25.gif differ diff --git a/httpserver/data/mew-neocities/library/2018-06-19_06-24-35.jpg b/httpserver/data/mew-neocities/library/2018-06-19_06-24-35.jpg new file mode 100644 index 0000000..89ef3bf Binary files /dev/null and b/httpserver/data/mew-neocities/library/2018-06-19_06-24-35.jpg differ diff --git a/httpserver/data/mew-neocities/library/2019-03-24_13-26-19.jpg b/httpserver/data/mew-neocities/library/2019-03-24_13-26-19.jpg new file mode 100644 index 0000000..717b23d Binary files /dev/null and b/httpserver/data/mew-neocities/library/2019-03-24_13-26-19.jpg differ diff --git a/httpserver/data/mew-neocities/library/2019-03-24_13-29-40.jpg b/httpserver/data/mew-neocities/library/2019-03-24_13-29-40.jpg new file mode 100644 index 0000000..e82f938 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2019-03-24_13-29-40.jpg differ diff --git a/httpserver/data/mew-neocities/library/2019-03-24_13-29-45.jpg b/httpserver/data/mew-neocities/library/2019-03-24_13-29-45.jpg new file mode 100644 index 0000000..10d1089 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2019-03-24_13-29-45.jpg differ diff --git a/httpserver/data/mew-neocities/library/2019-04-06_22-09-24.jpg b/httpserver/data/mew-neocities/library/2019-04-06_22-09-24.jpg new file mode 100644 index 0000000..2677839 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2019-04-06_22-09-24.jpg differ diff --git a/httpserver/data/mew-neocities/library/2019-06-26_16-42-51.jpg b/httpserver/data/mew-neocities/library/2019-06-26_16-42-51.jpg new file mode 100644 index 0000000..b777abc Binary files /dev/null and b/httpserver/data/mew-neocities/library/2019-06-26_16-42-51.jpg differ diff --git a/httpserver/data/mew-neocities/library/2019-06-26_16-43-14.jpg b/httpserver/data/mew-neocities/library/2019-06-26_16-43-14.jpg new file mode 100644 index 0000000..b993540 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2019-06-26_16-43-14.jpg differ diff --git a/httpserver/data/mew-neocities/library/2019-06-26_16-43-26.jpg b/httpserver/data/mew-neocities/library/2019-06-26_16-43-26.jpg new file mode 100644 index 0000000..3c7393a Binary files /dev/null and b/httpserver/data/mew-neocities/library/2019-06-26_16-43-26.jpg differ diff --git a/httpserver/data/mew-neocities/library/2019-06-26_16-44-49.jpg b/httpserver/data/mew-neocities/library/2019-06-26_16-44-49.jpg new file mode 100644 index 0000000..93fc984 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2019-06-26_16-44-49.jpg differ diff --git a/httpserver/data/mew-neocities/library/2019-06-26_16-45-05.jpg b/httpserver/data/mew-neocities/library/2019-06-26_16-45-05.jpg new file mode 100644 index 0000000..82257e7 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2019-06-26_16-45-05.jpg differ diff --git a/httpserver/data/mew-neocities/library/2019-06-26_16-45-15.jpg b/httpserver/data/mew-neocities/library/2019-06-26_16-45-15.jpg new file mode 100644 index 0000000..fa8f872 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2019-06-26_16-45-15.jpg differ diff --git a/httpserver/data/mew-neocities/library/2019-06-26_16-45-30.jpg b/httpserver/data/mew-neocities/library/2019-06-26_16-45-30.jpg new file mode 100644 index 0000000..77a50c9 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2019-06-26_16-45-30.jpg differ diff --git a/httpserver/data/mew-neocities/library/2019-08-13_22-25-52.jpg b/httpserver/data/mew-neocities/library/2019-08-13_22-25-52.jpg new file mode 100644 index 0000000..5c63d02 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2019-08-13_22-25-52.jpg differ diff --git a/httpserver/data/mew-neocities/library/2019-08-13_22-25-54.jpg b/httpserver/data/mew-neocities/library/2019-08-13_22-25-54.jpg new file mode 100644 index 0000000..7ea81aa Binary files /dev/null and b/httpserver/data/mew-neocities/library/2019-08-13_22-25-54.jpg differ diff --git a/httpserver/data/mew-neocities/library/2019-08-13_22-26-16.jpg b/httpserver/data/mew-neocities/library/2019-08-13_22-26-16.jpg new file mode 100644 index 0000000..469f53d Binary files /dev/null and b/httpserver/data/mew-neocities/library/2019-08-13_22-26-16.jpg differ diff --git a/httpserver/data/mew-neocities/library/2019-08-30_00-30-01.jpg b/httpserver/data/mew-neocities/library/2019-08-30_00-30-01.jpg new file mode 100644 index 0000000..282ab4d Binary files /dev/null and b/httpserver/data/mew-neocities/library/2019-08-30_00-30-01.jpg differ diff --git a/httpserver/data/mew-neocities/library/2019-09-02_23-22-36.jpg b/httpserver/data/mew-neocities/library/2019-09-02_23-22-36.jpg new file mode 100644 index 0000000..7ff0c91 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2019-09-02_23-22-36.jpg differ diff --git a/httpserver/data/mew-neocities/library/2019-09-04_14-44-02.jpg b/httpserver/data/mew-neocities/library/2019-09-04_14-44-02.jpg new file mode 100644 index 0000000..47baecb Binary files /dev/null and b/httpserver/data/mew-neocities/library/2019-09-04_14-44-02.jpg differ diff --git a/httpserver/data/mew-neocities/library/2019-09-09_13-43-30.jpg b/httpserver/data/mew-neocities/library/2019-09-09_13-43-30.jpg new file mode 100644 index 0000000..f7c67bf Binary files /dev/null and b/httpserver/data/mew-neocities/library/2019-09-09_13-43-30.jpg differ diff --git a/httpserver/data/mew-neocities/library/2019-09-09_13-43-34.jpg b/httpserver/data/mew-neocities/library/2019-09-09_13-43-34.jpg new file mode 100644 index 0000000..fe2832a Binary files /dev/null and b/httpserver/data/mew-neocities/library/2019-09-09_13-43-34.jpg differ diff --git a/httpserver/data/mew-neocities/library/2019-09-09_13-43-45.jpg b/httpserver/data/mew-neocities/library/2019-09-09_13-43-45.jpg new file mode 100644 index 0000000..9963752 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2019-09-09_13-43-45.jpg differ diff --git a/httpserver/data/mew-neocities/library/2019-09-10_03-28-24.jpg b/httpserver/data/mew-neocities/library/2019-09-10_03-28-24.jpg new file mode 100644 index 0000000..bea40a3 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2019-09-10_03-28-24.jpg differ diff --git a/httpserver/data/mew-neocities/library/2019-10-21_19-40-51.jpg b/httpserver/data/mew-neocities/library/2019-10-21_19-40-51.jpg new file mode 100644 index 0000000..92434ab Binary files /dev/null and b/httpserver/data/mew-neocities/library/2019-10-21_19-40-51.jpg differ diff --git a/httpserver/data/mew-neocities/library/2019-10-21_19-40-55.jpg b/httpserver/data/mew-neocities/library/2019-10-21_19-40-55.jpg new file mode 100644 index 0000000..3269729 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2019-10-21_19-40-55.jpg differ diff --git a/httpserver/data/mew-neocities/library/2019-11-29_10-37-37.jpg b/httpserver/data/mew-neocities/library/2019-11-29_10-37-37.jpg new file mode 100644 index 0000000..e336ac7 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2019-11-29_10-37-37.jpg differ diff --git a/httpserver/data/mew-neocities/library/2019-11-29_10-37-46.jpg b/httpserver/data/mew-neocities/library/2019-11-29_10-37-46.jpg new file mode 100644 index 0000000..392e67a Binary files /dev/null and b/httpserver/data/mew-neocities/library/2019-11-29_10-37-46.jpg differ diff --git a/httpserver/data/mew-neocities/library/2019-11-29_10-38-17.jpg b/httpserver/data/mew-neocities/library/2019-11-29_10-38-17.jpg new file mode 100644 index 0000000..af19c7d Binary files /dev/null and b/httpserver/data/mew-neocities/library/2019-11-29_10-38-17.jpg differ diff --git a/httpserver/data/mew-neocities/library/2019-11-29_10-38-30.jpg b/httpserver/data/mew-neocities/library/2019-11-29_10-38-30.jpg new file mode 100644 index 0000000..99af890 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2019-11-29_10-38-30.jpg differ diff --git a/httpserver/data/mew-neocities/library/2019-11-29_10-38-33.jpg b/httpserver/data/mew-neocities/library/2019-11-29_10-38-33.jpg new file mode 100644 index 0000000..66e2673 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2019-11-29_10-38-33.jpg differ diff --git a/httpserver/data/mew-neocities/library/2020-03-01_20-38-41.jpg b/httpserver/data/mew-neocities/library/2020-03-01_20-38-41.jpg new file mode 100644 index 0000000..90d9f22 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2020-03-01_20-38-41.jpg differ diff --git a/httpserver/data/mew-neocities/library/2020-03-01_20-38-43.jpg b/httpserver/data/mew-neocities/library/2020-03-01_20-38-43.jpg new file mode 100644 index 0000000..716aae5 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2020-03-01_20-38-43.jpg differ diff --git a/httpserver/data/mew-neocities/library/2020-04-04_21-31-48.jpg b/httpserver/data/mew-neocities/library/2020-04-04_21-31-48.jpg new file mode 100644 index 0000000..b21af09 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2020-04-04_21-31-48.jpg differ diff --git a/httpserver/data/mew-neocities/library/2020-04-13_07-47-36.jpg b/httpserver/data/mew-neocities/library/2020-04-13_07-47-36.jpg new file mode 100644 index 0000000..ddcd046 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2020-04-13_07-47-36.jpg differ diff --git a/httpserver/data/mew-neocities/library/2020-10-22_18-02-17.jpg b/httpserver/data/mew-neocities/library/2020-10-22_18-02-17.jpg new file mode 100644 index 0000000..fdb189e Binary files /dev/null and b/httpserver/data/mew-neocities/library/2020-10-22_18-02-17.jpg differ diff --git a/httpserver/data/mew-neocities/library/2022-02-09_10-09-03.jpg b/httpserver/data/mew-neocities/library/2022-02-09_10-09-03.jpg new file mode 100644 index 0000000..3554c86 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2022-02-09_10-09-03.jpg differ diff --git a/httpserver/data/mew-neocities/library/2022-02-09_10-09-26.jpg b/httpserver/data/mew-neocities/library/2022-02-09_10-09-26.jpg new file mode 100644 index 0000000..75f8e4e Binary files /dev/null and b/httpserver/data/mew-neocities/library/2022-02-09_10-09-26.jpg differ diff --git a/httpserver/data/mew-neocities/library/2022-02-09_10-09-53.jpg b/httpserver/data/mew-neocities/library/2022-02-09_10-09-53.jpg new file mode 100644 index 0000000..4dff8a8 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2022-02-09_10-09-53.jpg differ diff --git a/httpserver/data/mew-neocities/library/2022-02-09_10-10-09.jpg b/httpserver/data/mew-neocities/library/2022-02-09_10-10-09.jpg new file mode 100644 index 0000000..a445dcb Binary files /dev/null and b/httpserver/data/mew-neocities/library/2022-02-09_10-10-09.jpg differ diff --git a/httpserver/data/mew-neocities/library/2022-02-09_10-10-29.jpg b/httpserver/data/mew-neocities/library/2022-02-09_10-10-29.jpg new file mode 100644 index 0000000..92cc3f6 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2022-02-09_10-10-29.jpg differ diff --git a/httpserver/data/mew-neocities/library/2022-06-27_02-30-51.jpg b/httpserver/data/mew-neocities/library/2022-06-27_02-30-51.jpg new file mode 100644 index 0000000..6d66f97 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2022-06-27_02-30-51.jpg differ diff --git a/httpserver/data/mew-neocities/library/2022-07-17_13-51-33.jpg b/httpserver/data/mew-neocities/library/2022-07-17_13-51-33.jpg new file mode 100644 index 0000000..9119e56 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2022-07-17_13-51-33.jpg differ diff --git a/httpserver/data/mew-neocities/library/2022-09-20_17-01-50.jpg b/httpserver/data/mew-neocities/library/2022-09-20_17-01-50.jpg new file mode 100644 index 0000000..c584084 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2022-09-20_17-01-50.jpg differ diff --git a/httpserver/data/mew-neocities/library/2024-09-27_14-19-30.jpg b/httpserver/data/mew-neocities/library/2024-09-27_14-19-30.jpg new file mode 100644 index 0000000..260c789 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2024-09-27_14-19-30.jpg differ diff --git a/httpserver/data/mew-neocities/library/2024-12-26_00-42-51.jpg b/httpserver/data/mew-neocities/library/2024-12-26_00-42-51.jpg new file mode 100644 index 0000000..85e5693 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2024-12-26_00-42-51.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-03-19_11-19-46.jpg b/httpserver/data/mew-neocities/library/2025-03-19_11-19-46.jpg new file mode 100644 index 0000000..5315986 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-03-19_11-19-46.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-03-19_11-19-46_1.jpg b/httpserver/data/mew-neocities/library/2025-03-19_11-19-46_1.jpg new file mode 100644 index 0000000..019fe26 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-03-19_11-19-46_1.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-03-19_11-19-52.jpg b/httpserver/data/mew-neocities/library/2025-03-19_11-19-52.jpg new file mode 100644 index 0000000..1c3efee Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-03-19_11-19-52.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-03-19_12-07-08.jpg b/httpserver/data/mew-neocities/library/2025-03-19_12-07-08.jpg new file mode 100644 index 0000000..3b13353 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-03-19_12-07-08.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-03-19_12-07-08_1.jpg b/httpserver/data/mew-neocities/library/2025-03-19_12-07-08_1.jpg new file mode 100644 index 0000000..4af9c76 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-03-19_12-07-08_1.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-03-19_12-07-08_4.jpg b/httpserver/data/mew-neocities/library/2025-03-19_12-07-08_4.jpg new file mode 100644 index 0000000..70fb5ef Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-03-19_12-07-08_4.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-03-19_12-07-08_6.jpg b/httpserver/data/mew-neocities/library/2025-03-19_12-07-08_6.jpg new file mode 100644 index 0000000..a103e85 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-03-19_12-07-08_6.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-03-19_12-07-10.jpg b/httpserver/data/mew-neocities/library/2025-03-19_12-07-10.jpg new file mode 100644 index 0000000..c296a77 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-03-19_12-07-10.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-03-19_12-07-10_1.jpg b/httpserver/data/mew-neocities/library/2025-03-19_12-07-10_1.jpg new file mode 100644 index 0000000..a7bed44 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-03-19_12-07-10_1.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-03-19_12-07-10_3.jpg b/httpserver/data/mew-neocities/library/2025-03-19_12-07-10_3.jpg new file mode 100644 index 0000000..f73c51c Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-03-19_12-07-10_3.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-03-19_12-07-10_5.jpg b/httpserver/data/mew-neocities/library/2025-03-19_12-07-10_5.jpg new file mode 100644 index 0000000..74b7a27 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-03-19_12-07-10_5.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-03-19_12-07-10_7.jpg b/httpserver/data/mew-neocities/library/2025-03-19_12-07-10_7.jpg new file mode 100644 index 0000000..39136a8 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-03-19_12-07-10_7.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-03-19_12-07-12.jpg b/httpserver/data/mew-neocities/library/2025-03-19_12-07-12.jpg new file mode 100644 index 0000000..cddfb72 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-03-19_12-07-12.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-03-19_12-07-14_1.jpg b/httpserver/data/mew-neocities/library/2025-03-19_12-07-14_1.jpg new file mode 100644 index 0000000..082be83 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-03-19_12-07-14_1.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-03-21_03-25-56.jpg b/httpserver/data/mew-neocities/library/2025-03-21_03-25-56.jpg new file mode 100644 index 0000000..7ddcc9c Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-03-21_03-25-56.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-03-21_03-26-06.jpg b/httpserver/data/mew-neocities/library/2025-03-21_03-26-06.jpg new file mode 100644 index 0000000..50ef2d4 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-03-21_03-26-06.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-03-21_03-26-22.jpg b/httpserver/data/mew-neocities/library/2025-03-21_03-26-22.jpg new file mode 100644 index 0000000..e8e62fb Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-03-21_03-26-22.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-03-25_20-37-12.jpg b/httpserver/data/mew-neocities/library/2025-03-25_20-37-12.jpg new file mode 100644 index 0000000..db72526 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-03-25_20-37-12.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-04-09_01-28-26.jpg b/httpserver/data/mew-neocities/library/2025-04-09_01-28-26.jpg new file mode 100644 index 0000000..2ceab33 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-04-09_01-28-26.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-04-09_01-28-32.jpg b/httpserver/data/mew-neocities/library/2025-04-09_01-28-32.jpg new file mode 100644 index 0000000..476a6c2 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-04-09_01-28-32.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-04-27_22-31-02.jpg b/httpserver/data/mew-neocities/library/2025-04-27_22-31-02.jpg new file mode 100644 index 0000000..b9cb8c8 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-04-27_22-31-02.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-04-27_22-31-02_1.jpg b/httpserver/data/mew-neocities/library/2025-04-27_22-31-02_1.jpg new file mode 100644 index 0000000..109a51a Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-04-27_22-31-02_1.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-06-22_05-33-20.jpg b/httpserver/data/mew-neocities/library/2025-06-22_05-33-20.jpg new file mode 100644 index 0000000..6aaa4c0 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-06-22_05-33-20.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-06-22_05-33-42.jpg b/httpserver/data/mew-neocities/library/2025-06-22_05-33-42.jpg new file mode 100644 index 0000000..f4c9f11 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-06-22_05-33-42.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-09-03_01-42-43.jpg b/httpserver/data/mew-neocities/library/2025-09-03_01-42-43.jpg new file mode 100644 index 0000000..1da155d Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-09-03_01-42-43.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-09-03_04-33-34.jpg b/httpserver/data/mew-neocities/library/2025-09-03_04-33-34.jpg new file mode 100644 index 0000000..1e91dfc Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-09-03_04-33-34.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-09-03_08-42-26.jpg b/httpserver/data/mew-neocities/library/2025-09-03_08-42-26.jpg new file mode 100644 index 0000000..118358f Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-09-03_08-42-26.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-10-16_16-07-12.jpg b/httpserver/data/mew-neocities/library/2025-10-16_16-07-12.jpg new file mode 100644 index 0000000..2d11ffb Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-10-16_16-07-12.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-11-02_05-22-30.jpg b/httpserver/data/mew-neocities/library/2025-11-02_05-22-30.jpg new file mode 100644 index 0000000..5a496bc Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-11-02_05-22-30.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-11-20_19-10-28.jpg b/httpserver/data/mew-neocities/library/2025-11-20_19-10-28.jpg new file mode 100644 index 0000000..69a8247 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-11-20_19-10-28.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-11-29_23-05-00.jpg b/httpserver/data/mew-neocities/library/2025-11-29_23-05-00.jpg new file mode 100644 index 0000000..7f9065d Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-11-29_23-05-00.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-11-29_23-05-02.jpg b/httpserver/data/mew-neocities/library/2025-11-29_23-05-02.jpg new file mode 100644 index 0000000..eed953b Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-11-29_23-05-02.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-11-29_23-05-04.jpg b/httpserver/data/mew-neocities/library/2025-11-29_23-05-04.jpg new file mode 100644 index 0000000..9387217 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-11-29_23-05-04.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-12-01_05-01-50.jpg b/httpserver/data/mew-neocities/library/2025-12-01_05-01-50.jpg new file mode 100644 index 0000000..7f09ed1 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-12-01_05-01-50.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-12-01_05-02-00.jpg b/httpserver/data/mew-neocities/library/2025-12-01_05-02-00.jpg new file mode 100644 index 0000000..82281c1 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-12-01_05-02-00.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-12-01_05-02-08.jpg b/httpserver/data/mew-neocities/library/2025-12-01_05-02-08.jpg new file mode 100644 index 0000000..e2d8a59 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-12-01_05-02-08.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-12-01_05-02-10.jpg b/httpserver/data/mew-neocities/library/2025-12-01_05-02-10.jpg new file mode 100644 index 0000000..c40489b Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-12-01_05-02-10.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-12-08_03-52-02.jpg b/httpserver/data/mew-neocities/library/2025-12-08_03-52-02.jpg new file mode 100644 index 0000000..f4944bf Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-12-08_03-52-02.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-12-08_03-52-12.jpg b/httpserver/data/mew-neocities/library/2025-12-08_03-52-12.jpg new file mode 100644 index 0000000..9c5a001 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-12-08_03-52-12.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-12-15_18-54-22.jpg b/httpserver/data/mew-neocities/library/2025-12-15_18-54-22.jpg new file mode 100644 index 0000000..c3078ae Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-12-15_18-54-22.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-12-15_18-54-28.jpg b/httpserver/data/mew-neocities/library/2025-12-15_18-54-28.jpg new file mode 100644 index 0000000..2767293 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-12-15_18-54-28.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-12-19_02-17-50.jpg b/httpserver/data/mew-neocities/library/2025-12-19_02-17-50.jpg new file mode 100644 index 0000000..ac294c2 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-12-19_02-17-50.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-12-23_10-36-00.jpg b/httpserver/data/mew-neocities/library/2025-12-23_10-36-00.jpg new file mode 100644 index 0000000..0284b1b Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-12-23_10-36-00.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-12-23_10-36-14.jpg b/httpserver/data/mew-neocities/library/2025-12-23_10-36-14.jpg new file mode 100644 index 0000000..c938fd5 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-12-23_10-36-14.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-12-23_10-36-16.jpg b/httpserver/data/mew-neocities/library/2025-12-23_10-36-16.jpg new file mode 100644 index 0000000..050f824 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-12-23_10-36-16.jpg differ diff --git a/httpserver/data/mew-neocities/library/2025-12-28_01-29-12.jpg b/httpserver/data/mew-neocities/library/2025-12-28_01-29-12.jpg new file mode 100644 index 0000000..47d6dbd Binary files /dev/null and b/httpserver/data/mew-neocities/library/2025-12-28_01-29-12.jpg differ diff --git a/httpserver/data/mew-neocities/library/2026-01-03_11-49-00.jpg b/httpserver/data/mew-neocities/library/2026-01-03_11-49-00.jpg new file mode 100644 index 0000000..2f7fd6f Binary files /dev/null and b/httpserver/data/mew-neocities/library/2026-01-03_11-49-00.jpg differ diff --git a/httpserver/data/mew-neocities/library/2026-01-17_16-17-34.jpg b/httpserver/data/mew-neocities/library/2026-01-17_16-17-34.jpg new file mode 100644 index 0000000..aadea97 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2026-01-17_16-17-34.jpg differ diff --git a/httpserver/data/mew-neocities/library/2026-02-13_14-55-30.jpg b/httpserver/data/mew-neocities/library/2026-02-13_14-55-30.jpg new file mode 100644 index 0000000..2309ed4 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2026-02-13_14-55-30.jpg differ diff --git a/httpserver/data/mew-neocities/library/2026-02-13_14-55-48.jpg b/httpserver/data/mew-neocities/library/2026-02-13_14-55-48.jpg new file mode 100644 index 0000000..7d41ed1 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2026-02-13_14-55-48.jpg differ diff --git a/httpserver/data/mew-neocities/library/2026-02-20_11-14-05.jpg b/httpserver/data/mew-neocities/library/2026-02-20_11-14-05.jpg new file mode 100644 index 0000000..60290fb Binary files /dev/null and b/httpserver/data/mew-neocities/library/2026-02-20_11-14-05.jpg differ diff --git a/httpserver/data/mew-neocities/library/2026-02-20_11-14-15.jpg b/httpserver/data/mew-neocities/library/2026-02-20_11-14-15.jpg new file mode 100644 index 0000000..7433594 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2026-02-20_11-14-15.jpg differ diff --git a/httpserver/data/mew-neocities/library/2026-02-20_11-14-18.jpg b/httpserver/data/mew-neocities/library/2026-02-20_11-14-18.jpg new file mode 100644 index 0000000..6a49aab Binary files /dev/null and b/httpserver/data/mew-neocities/library/2026-02-20_11-14-18.jpg differ diff --git a/httpserver/data/mew-neocities/library/2026-02-20_11-14-23.jpg b/httpserver/data/mew-neocities/library/2026-02-20_11-14-23.jpg new file mode 100644 index 0000000..2fd6a43 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2026-02-20_11-14-23.jpg differ diff --git a/httpserver/data/mew-neocities/library/2026-02-20_11-14-26.jpg b/httpserver/data/mew-neocities/library/2026-02-20_11-14-26.jpg new file mode 100644 index 0000000..2a7e025 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2026-02-20_11-14-26.jpg differ diff --git a/httpserver/data/mew-neocities/library/2026-02-20_13-11-03.jpg b/httpserver/data/mew-neocities/library/2026-02-20_13-11-03.jpg new file mode 100644 index 0000000..ae8f500 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2026-02-20_13-11-03.jpg differ diff --git a/httpserver/data/mew-neocities/library/2026-02-20_14-29-46.jpg b/httpserver/data/mew-neocities/library/2026-02-20_14-29-46.jpg new file mode 100644 index 0000000..377ecaf Binary files /dev/null and b/httpserver/data/mew-neocities/library/2026-02-20_14-29-46.jpg differ diff --git a/httpserver/data/mew-neocities/library/2026-02-22_08-01-22.jpg b/httpserver/data/mew-neocities/library/2026-02-22_08-01-22.jpg new file mode 100644 index 0000000..953a9ff Binary files /dev/null and b/httpserver/data/mew-neocities/library/2026-02-22_08-01-22.jpg differ diff --git a/httpserver/data/mew-neocities/library/2026-02-22_08-47-23.jpg b/httpserver/data/mew-neocities/library/2026-02-22_08-47-23.jpg new file mode 100644 index 0000000..9cda587 Binary files /dev/null and b/httpserver/data/mew-neocities/library/2026-02-22_08-47-23.jpg differ diff --git a/httpserver/data/mew-neocities/library/doit.sh b/httpserver/data/mew-neocities/library/doit.sh new file mode 100644 index 0000000..59e70db --- /dev/null +++ b/httpserver/data/mew-neocities/library/doit.sh @@ -0,0 +1,61 @@ +#!/usr/bin/env bash +# Renames images and videos in ./ based on metadata date +# Requires: exiftool +# Format: YYYY-MM-DD_HH-MM-SS.ext (appends _N if duplicate) + +set -euo pipefail + +TARGET="${1:-.}" + +if ! command -v exiftool &>/dev/null; then + echo "Error: exiftool not found. Install it with: sudo apt install libimage-exiftool-perl" >&2 + exit 1 +fi + +shopt -s nullglob nocaseglob +files=("$TARGET"/*.{jpg,jpeg,png,tiff,tif,heic,webp,mp4,mov,m4v,avi,mkv,webm}) +shopt -u nullglob nocaseglob + +if [[ ${#files[@]} -eq 0 ]]; then + echo "No image files found in: $TARGET" + exit 0 +fi + +for file in "${files[@]}"; do + [[ -f "$file" ]] || continue + + dir=$(dirname "$file") + ext="${file##*.}" + ext_lower="${ext,,}" + + # Try date tags in priority order + date_str=$(exiftool -d "%Y-%m-%d_%H-%M-%S" \ + -DateTimeOriginal \ + -CreateDate \ + -ModifyDate \ + -FileModifyDate \ + -s3 "$file" 2>/dev/null | head -1) + + if [[ -z "$date_str" || "$date_str" == *"0000"* ]]; then + echo "SKIP (no date): $file" + continue + fi + + new_base="$dir/${date_str}.${ext_lower}" + + # Handle duplicates + if [[ "$file" == "$new_base" ]]; then + echo "OK (unchanged): $file" + continue + fi + + counter=1 + final="$new_base" + while [[ -e "$final" ]]; do + final="$dir/${date_str}_${counter}.${ext_lower}" + ((counter++)) + done + + mv -- "$file" "$final" + echo "RENAMED: $(basename "$file") -> $(basename "$final")" +done diff --git a/httpserver/data/mew-neocities/library/mp4-to-gif.sh b/httpserver/data/mew-neocities/library/mp4-to-gif.sh new file mode 100755 index 0000000..7bdbd34 --- /dev/null +++ b/httpserver/data/mew-neocities/library/mp4-to-gif.sh @@ -0,0 +1,87 @@ +#!/usr/bin/env bash +# Convert Mew timeline MP4 clips into small, optimized GIFs for Neocities. +# Requires: ffmpeg, gifsicle +# +# Strategy: +# - Trim to the first few seconds +# - Sample only a few frames per second +# - Scale down to a small width +# - Use a global palette + heavy optimization +# - Aim to keep each GIF under ~5MB +# +# Usage (from this directory): +# chmod +x mp4-to-gif.sh +# ./mp4-to-gif.sh /path/to/source/mp4s + +set -euo pipefail + +SRC_DIR="${1:-.}" +OUT_DIR="${OUT_DIR:-.}" + +# Tunables for size/quality tradeoff +FPS="${FPS:-3}" # frames per second sampled +WIDTH="${WIDTH:-360}" # output width in pixels +MAX_SECONDS="${MAX_SECONDS:-8}" # cap duration + +if ! command -v ffmpeg &>/dev/null; then + echo "Error: ffmpeg not found. Install it first." >&2 + exit 1 +fi + +if ! command -v gifsicle &>/dev/null; then + echo "Warning: gifsicle not found. Skipping extra optimization (GIFs may be larger)." >&2 +fi + +convert_one () { + local name="$1" # e.g. 2016-12-17_22-42-58 + local in="$SRC_DIR/${name}.mp4" + + # Unique temp files to avoid name clashes if run multiple times + local pal + pal="$(mktemp "${OUT_DIR}/${name}-palette-XXXX.png")" + local out_tmp + out_tmp="$(mktemp "${OUT_DIR}/${name}-tmp-XXXX.gif")" + local out_final="${OUT_DIR}/${name}.gif" + + if [[ ! -f "$in" ]]; then + echo "Skip (missing): $in" + return + fi + + echo "Processing $in -> $out_final" + + # 1) Generate palette from trimmed, sparsely sampled, scaled frames + ffmpeg -y -t "$MAX_SECONDS" -i "$in" \ + -vf "fps=${FPS},scale=${WIDTH}:-1:flags=lanczos,palettegen=stats_mode=single:max_colors=48" \ + -frames:v 1 \ + "$pal" + + # 2) Apply palette to create GIF + ffmpeg -y -t "$MAX_SECONDS" -i "$in" -i "$pal" \ + -lavfi "fps=${FPS},scale=${WIDTH}:-1:flags=lanczos [x]; [x][1:v] paletteuse=dither=bayer:bayer_scale=5:diff_mode=rectangle" \ + -loop 0 \ + "$out_tmp" + + # 3) Extra optimization with gifsicle, if available + if command -v gifsicle &>/dev/null; then + gifsicle -O3 --lossy=40 "$out_tmp" -o "$out_final" + rm -f "$out_tmp" + else + mv "$out_tmp" "$out_final" + fi + + rm -f "$pal" + + # 4) Print size + if command -v du &>/dev/null; then + echo -n "Final size: " + du -h "$out_final" | cut -f1 + fi +} + +convert_one "2016-12-17_22-42-58" +convert_one "2017-04-01_00-14-00" +convert_one "2018-06-19_06-20-25" + +echo "Done. Upload the generated *.gif files to the 'library' folder on Neocities and ensure index.html references the .gif versions." + diff --git a/httpserver/data/mew-neocities/library/webp-to-jpg.sh b/httpserver/data/mew-neocities/library/webp-to-jpg.sh new file mode 100755 index 0000000..0cd9fc5 --- /dev/null +++ b/httpserver/data/mew-neocities/library/webp-to-jpg.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash +# Create JPG versions of all WEBP images in a folder, +# resizing them to roughly 2–3 megapixels while preserving aspect ratio. +# Uses ffmpeg. +# +# Usage (from any directory): +# OUT_DIR="." ./webp-to-jpg.sh /path/to/webp/folder +# +# Defaults: +# SRC_DIR = first argument (or ".") +# OUT_DIR = $OUT_DIR (or ".") +# MAX_DIM = longest side in pixels (default 2000) + +set -euo pipefail + +SRC_DIR="${1:-.}" +OUT_DIR="${OUT_DIR:-.}" +MAX_DIM="${MAX_DIM:-2000}" # longest side; typical outputs end up ~2–3 MP +QUALITY="${QUALITY:-3}" # ffmpeg JPEG quality (2–4 is usually fine) + +if ! command -v ffmpeg &>/dev/null; then + echo "Error: ffmpeg not found. Install it first." >&2 + exit 1 +fi + +shopt -s nullglob nocaseglob +files=("$SRC_DIR"/*.webp) +shopt -u nullglob nocaseglob + +if [[ ${#files[@]} -eq 0 ]]; then + echo "No WEBP files found in: $SRC_DIR" + exit 0 +fi + +mkdir -p "$OUT_DIR" + +for in_path in "${files[@]}"; do + base="$(basename "$in_path")" + name="${base%.*}" + out_path="${OUT_DIR}/${name}.jpg" + + echo "Converting $in_path -> $out_path" + + # Scale so that the longest side is MAX_DIM, preserving aspect ratio. + # This may upscale small images slightly, which is acceptable here. + ffmpeg -y -i "$in_path" \ + -vf "scale='if(gt(iw,ih),${MAX_DIM},-2)':'if(gte(ih,iw),${MAX_DIM},-2)'" \ + -q:v "$QUALITY" \ + "$out_path" +done + +echo "Done creating JPG versions in: $OUT_DIR" + diff --git a/httpserver/data/mew/index.html b/httpserver/data/mew/index.html new file mode 100644 index 0000000..5873d1a --- /dev/null +++ b/httpserver/data/mew/index.html @@ -0,0 +1,47 @@ + + + + + + Page Moved + + + + +
+

This page moved to:

+

https://mewbuttpie.neocities.org

+ + Redirect Image +
+ + + diff --git a/httpserver/data/package-lock.json b/httpserver/data/package-lock.json new file mode 100644 index 0000000..a9fdb72 --- /dev/null +++ b/httpserver/data/package-lock.json @@ -0,0 +1,36 @@ +{ + "name": "http-srv", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "http-srv", + "version": "1.0.0", + "dependencies": { + "ws": "8.18.0" + } + }, + "node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + } + } +} diff --git a/httpserver/data/package.json b/httpserver/data/package.json new file mode 100644 index 0000000..92e72f3 --- /dev/null +++ b/httpserver/data/package.json @@ -0,0 +1,12 @@ +{ + "name": "http-srv", + "version": "1.0.0", + "description": "Static site and real-time chat backend", + "private": true, + "scripts": { + "chat": "node chat-server.js" + }, + "dependencies": { + "ws": "8.18.0" + } +} diff --git a/httpserver/data/services-data.json b/httpserver/data/services-data.json new file mode 100644 index 0000000..b2939cc --- /dev/null +++ b/httpserver/data/services-data.json @@ -0,0 +1,287 @@ +{ + "services": [ + { + "name": "Jellyfin", + "url": "https://jfin.gravitywell.xyz", + "category": "Multimedia", + "icon": "🎬", + "active": true, + "meta": [ + { + "label": "Onion", + "url": "https://ser77s6g3yhn47auyqfyupbm4odncjmnfatqmxzebiz2fe5tw5emdhyd.onion" + }, + { + "label": "Register", + "url": "https://wiz.gravitywell.xyz/j/FCKNFLX" + } + ] + }, + { + "name": "Jellyseerr", + "url": "https://seerr.gravitywell.xyz", + "category": "Multimedia", + "icon": "🎬", + "active": true + }, + { + "name": "Stoat", + "url": "https://stoat.gravitywell.xyz", + "category": "Communications", + "icon": "💬", + "active": true + }, + { + "name": "NaviDrome", + "url": "https://navi.gravitywell.xyz", + "category": "Audio Streaming", + "icon": "🎵", + "active": true + }, + { + "name": "Feishin", + "url": "https://feishin.gravitywell.xyz/", + "category": "Audio Streaming", + "icon": "🎵", + "active": true + }, + { + "name": "FunkWhale", + "url": "https://funk.gravitywell.xyz", + "category": "Audio Streaming", + "icon": "🎵", + "active": true, + "status": "down" + }, + { + "name": "Romm", + "url": "https://romm.gravitywell.xyz", + "category": "Games & Emulation", + "icon": "🎮", + "active": true, + "meta": [ + { + "label": "Register", + "url": "https://wiz.gravitywell.xyz/j/NTDOYSUX" + } + ] + }, + { + "name": "Akkoma", + "url": "https://pl.ugh.im", + "category": "Fediverse", + "icon": "🌐", + "active": true + }, + { + "name": "Lemmy", + "url": "https://lem.ugh.im/", + "category": "Fediverse", + "icon": "🌐", + "active": true + }, + { + "name": "PieFed", + "url": "https://pie.gravitywell.xyz", + "category": "Fediverse", + "icon": "🌐", + "active": true + }, + { + "name": "PeerTube", + "url": "https://peertube.gravitywell.xyz", + "category": "Fediverse", + "icon": "🌐", + "active": true + }, + { + "name": "Primal", + "url": "https://primal.gravitywell.xyz", + "category": "Nostr", + "icon": "⚡", + "active": true, + "meta": [ + { + "label": "Alt", + "url": "https://prml.ugh.im" + } + ] + }, + { + "name": "nostrudel", + "url": "https://nostrudel.gravitywell.xyz", + "category": "Nostr", + "icon": "⚡", + "active": true, + "meta": [ + { + "label": "Alt", + "url": "https://nsdl.ugh.im" + } + ] + }, + { + "name": "MiroChat", + "url": "https://talk.gravitywell.xyz/", + "category": "Communications", + "icon": "💬", + "active": true + }, + { + "name": "Rocket.Chat", + "url": "https://rocketchat.gravitywell.xyz", + "category": "Communications", + "icon": "💬", + "active": true + }, + { + "name": "Floatilla", + "url": "https://floatilla.gravitywell.xyz/", + "category": "Nostr", + "icon": "⚡", + "active": true, + "meta": [ + { + "label": "Alt", + "url": "https://flt.ugh.im" + } + ] + }, + { + "name": "Piped", + "url": "https://piped.gravitywell.xyz", + "category": "Privacy Front Ends", + "icon": "🔒", + "active": true, + "meta": [ + { + "label": "Alt", + "url": "https://piped.ugh.im" + } + ] + }, + { + "name": "Rimgo", + "url": "https://rimgo.gravitywell.xyz", + "category": "Privacy Front Ends", + "icon": "🔒", + "active": true, + "meta": [ + { + "label": "Alt", + "url": "https://rmg.ugh.im" + } + ] + }, + { + "name": "Quetre", + "url": "https://quetre.gravitywell.xyz", + "category": "Privacy Front Ends", + "icon": "🔒", + "active": true + }, + { + "name": "Redlib", + "url": "https://redlib.gravitywell.xyz", + "category": "Privacy Front Ends", + "icon": "🔒", + "active": true, + "meta": [ + { + "label": "Alt", + "url": "https://rd.ugh.im" + } + ] + }, + { + "name": "SearXNG", + "url": "https://searx.gravitywell.xyz", + "category": "Privacy Front Ends", + "icon": "🔒", + "active": true, + "meta": [ + { + "label": "Alt", + "url": "https://searx.ugh.im" + } + ] + }, + { + "name": "Dumb", + "url": "https://dumb.gravitywell.xyz", + "category": "Privacy Front Ends", + "icon": "🔒", + "active": true + }, + { + "name": "NextCloud", + "url": "https://cloud.gravitywell.xyz", + "category": "Office & Productivity", + "icon": "📝", + "active": true + }, + { + "name": "PrivateBin", + "url": "https://pb.ugh.im", + "category": "Office & Productivity", + "icon": "📝", + "active": true + }, + { + "name": "Vikunja", + "url": "https://tasks.gravitywell.xyz", + "category": "Office & Productivity", + "icon": "📝", + "active": true, + "status": "down" + }, + { + "name": "FreshRSS", + "url": "https://fr.ugh.im", + "category": "Office & Productivity", + "icon": "📝", + "active": true + }, + { + "name": "HedgeDoc", + "url": "https://hd.ugh.im", + "category": "Office & Productivity", + "icon": "📝", + "active": true + }, + { + "name": "Linkwarden", + "url": "https://lw.gravitywell.xyz", + "category": "Office & Productivity", + "icon": "📝", + "active": true + }, + { + "name": "ByteStash", + "url": "https://bs.ugh.im", + "category": "Office & Productivity", + "icon": "📝", + "active": true + }, + { + "name": "OpenSpeedTest", + "url": "https://speedtest.gravitywell.xyz", + "category": "Utilities", + "icon": "🛠️", + "active": true, + "meta": [ + { + "label": "Alt", + "url": "https://st.ugh.im" + } + ] + }, + { + "name": "Uptime Kuma", + "url": "https://ut.ugh.im/status/prime", + "category": "Utilities", + "icon": "🛠️", + "active": true + } + ] +} \ No newline at end of file diff --git a/httpserver/data/services-loader.js b/httpserver/data/services-loader.js new file mode 100644 index 0000000..3724d68 --- /dev/null +++ b/httpserver/data/services-loader.js @@ -0,0 +1,286 @@ +/** + * Service Data Loader + * This script loads services from services-data.json and provides helper functions + * to render them in different HTML structures for gw.html and ugh.html + * + * NOTE: Services are loaded from JSON at runtime (expected to be served over HTTP). + * Edit `services-data.json` to update the service directory. + */ + +// Capture data-services-url at load time (for archived pages in subdirs) +const SERVICES_JSON_URL = (function () { + const s = document.currentScript; + return (s && s.dataset.servicesUrl) ? s.dataset.servicesUrl : 'services-data.json'; +})(); + +// Load and cache the services data +let servicesData = null; + +async function loadServicesData() { + if (servicesData) return servicesData; + + try { + const response = await fetch(SERVICES_JSON_URL); + if (response.ok) { + servicesData = await response.json(); + return servicesData; + } + console.warn(`Failed to load ${SERVICES_JSON_URL}: HTTP ${response.status}`); + } catch (err) { + console.warn(`Failed to load ${SERVICES_JSON_URL}:`, err); + } + + // No data available (e.g. file:// protocol or missing JSON) + servicesData = { services: [] }; + return servicesData; +} + +// Group services by category +function groupByCategory(services) { + const grouped = {}; + services.forEach(service => { + if (!grouped[service.category]) { + grouped[service.category] = []; + } + grouped[service.category].push(service); + }); + return grouped; +} + +// Split services into active (Ugh, GS, GW) and archived +function splitActiveArchived(services) { + const active = []; + const archived = []; + services.forEach(service => { + if (service.active !== false) { + active.push(service); + } else { + archived.push(service); + } + }); + return { active, archived }; +} + +// Escape for HTML text content (defense-in-depth against XSS from service data) +function escapeHtml(str) { + if (typeof str !== 'string') return ''; + return str.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); +} + +// Escape for HTML attribute values (e.g. href) +function escapeAttr(str) { + if (typeof str !== 'string') return ''; + return str.replace(/&/g, '&').replace(/"/g, '"').replace(/'/g, ''').replace(//g, '>'); +} + +function isFlaggedDown(service) { + return service && (service.status === 'down' || service.status === 'maintenance'); +} + +// Render one service list (used for both active and archived blocks) +function renderServiceGroupHtml(grouped, options = {}) { + let html = ''; + const { showArchivedStyle = false } = options; + for (const [category, services] of Object.entries(grouped)) { + html += ` +
+

${escapeHtml(category)}

+
    `; + services.forEach(service => { + html += ` +
  • + ${escapeHtml(service.name)}`; + if (service.meta && service.meta.length > 0) { + html += ` `; + service.meta.forEach((meta, index) => { + html += `${index > 0 ? ' | ' : '| '}[${escapeHtml(meta.label)}]`; + }); + html += ``; + } + html += ` +
  • `; + }); + html += ` +
+
`; + } + return html; +} + +// Render services for gw.html (minimalist style): Active first, then Archived +function renderServicesForGW(containerId) { + loadServicesData().then(data => { + const container = document.getElementById(containerId); + if (!container) return; + + const { active, archived } = splitActiveArchived(data.services); + let html = ''; + + if (active.length > 0) { + html += `

Active (Ugh · GW)

`; + html += renderServiceGroupHtml(groupByCategory(active)); + } + + if (archived.length > 0) { + html += `
+ Archived services +
`; + html += renderServiceGroupHtml(groupByCategory(archived), { showArchivedStyle: true }); + html += `
`; + } + + container.innerHTML = html; + }); +} + +// Render services for ugh.html (retro style) — active only +function renderServicesForUGH(containerId) { + loadServicesData().then(data => { + const container = document.getElementById(containerId); + if (!container) return; + + const { active } = splitActiveArchived(data.services); + const grouped = groupByCategory(active); + let html = ''; + + for (const [category, services] of Object.entries(grouped)) { + html += ` +
+

${escapeHtml(services[0].icon || '')} ${escapeHtml(category)}

+
    `; + + services.forEach(service => { + html += ` +
  • + ${escapeHtml(service.name)}`; + + // Add meta links if they exist + if (service.meta && service.meta.length > 0) { + service.meta.forEach(meta => { + html += ` + [${escapeHtml(meta.label)}]`; + }); + } + + html += ` +
  • `; + }); + + html += ` +
+
`; + } + + container.innerHTML = html; + }); +} + +// Render services for future.html (dropdown menu, futuristic theme) +function renderServicesForFuture(containerId) { + loadServicesData().then(data => { + const container = document.getElementById(containerId); + if (!container) return; + + container.classList.add('loading'); + const { active, archived } = splitActiveArchived(data.services); + const activeGrouped = groupByCategory(active); + const archivedGrouped = groupByCategory(archived); + + let html = '

SERVICE DIRECTORY

'; + + // Active services as dropdowns + for (const [category, services] of Object.entries(activeGrouped)) { + const icon = escapeHtml(services[0].icon || '◆'); + const id = 'fd-' + category.replace(/[^a-zA-Z0-9\s-]/g, '').replace(/\s+/g, '-').toLowerCase(); + html += ` +
+ +
+
`; + services.forEach(service => { + html += ` +
+ ${escapeHtml(service.name)}`; + if (service.meta && service.meta.length > 0) { + html += '
'; + service.meta.forEach(meta => { + html += `${escapeHtml(meta.label)}`; + }); + html += '
'; + } + html += '
'; + }); + html += ` +
+
+
`; + } + + // Archived services + if (archived.length > 0) { + html += `
+ ARCHIVED SERVICES +
`; + for (const [category, services] of Object.entries(archivedGrouped)) { + const icon = escapeHtml(services[0].icon || '◆'); + const id = 'fd-arch-' + category.replace(/[^a-zA-Z0-9\s-]/g, '').replace(/\s+/g, '-').toLowerCase(); + html += ` +
+ +
+
`; + services.forEach(service => { + html += ` +
+ ${escapeHtml(service.name)}`; + if (service.meta && service.meta.length > 0) { + html += '
'; + service.meta.forEach(meta => { + html += `${escapeHtml(meta.label)}`; + }); + html += '
'; + } + html += '
'; + }); + html += ` +
+
+
`; + } + html += `
`; + } + + container.innerHTML = html; + container.classList.remove('loading'); + + // Attach click handlers for dropdowns + container.querySelectorAll('.future-dropdown-trigger').forEach(btn => { + btn.addEventListener('click', function () { + const dd = this.closest('.future-dropdown'); + dd.classList.toggle('open'); + btn.setAttribute('aria-expanded', dd.classList.contains('open')); + }); + }); + }); +} + +// Export functions for use in other scripts +if (typeof module !== 'undefined' && module.exports) { + module.exports = { + loadServicesData, + groupByCategory, + renderServicesForGW, + renderServicesForUGH, + renderServicesForFuture + }; +} diff --git a/httpserver/data/ugh-bloodlust.css b/httpserver/data/ugh-bloodlust.css new file mode 100644 index 0000000..6c6f4a0 --- /dev/null +++ b/httpserver/data/ugh-bloodlust.css @@ -0,0 +1,301 @@ +/** + * UGH.im — Bloodlust Edition + * NESticle / Genecyst / Bloodlust Software aesthetic + * Dark, polarizing, 90s emulator skin vibe + */ + +:root { + --bl-bg: #0a0808; + --bl-bg-panel: #0d0a0a; + --bl-bg-inner: #0f0c0c; + --bl-border-light: #2a2525; + --bl-border-dark: #1a1616; + --bl-green: #00cc66; + --bl-green-dim: #008844; + --bl-red: #cc3333; + --bl-red-dim: #991111; + --bl-text: #c0c0c0; + --bl-text-dim: #808080; + --bl-mono: "Share Tech Mono", "VT323", "Courier New", monospace; + --bl-display: "VT323", "Share Tech Mono", monospace; +} + +* { margin: 0; padding: 0; box-sizing: border-box; } + +html { scroll-behavior: smooth; } + +body { + background: var(--bl-bg); + color: var(--bl-text); + font-family: var(--bl-mono); + font-size: 14px; + line-height: 1.5; + min-height: 100vh; +} + +a { + color: var(--bl-green); + text-decoration: none; +} + +a:hover { color: #33ff99; } + +/* CRT / Scanline overlay */ +.scanlines { + position: fixed; + inset: 0; + pointer-events: none; + z-index: 9999; + background: repeating-linear-gradient( + 0deg, + transparent, + transparent 2px, + rgba(0, 0, 0, 0.15) 2px, + rgba(0, 0, 0, 0.15) 4px + ); + opacity: 0.4; +} + +.crt-glow { + position: fixed; + inset: 0; + pointer-events: none; + z-index: -1; + background: radial-gradient(ellipse at center, transparent 0%, rgba(0, 0, 0, 0.6) 100%); +} + +/* Main frame - window border */ +.frame { + max-width: 680px; + margin: 1rem auto; + border: 4px solid var(--bl-border-light); + border-style: outset; + box-shadow: + inset 2px 2px 0 rgba(255, 255, 255, 0.05), + inset -2px -2px 0 rgba(0, 0, 0, 0.5), + 0 0 0 2px var(--bl-border-dark); + background: var(--bl-bg-panel); +} + +/* Title bar - NESticle-style */ +.title-bar { + background: linear-gradient(180deg, #1a1616 0%, #0d0a0a 100%); + border-bottom: 2px solid var(--bl-red-dim); + padding: 0.4rem 1rem; + display: flex; + align-items: center; + justify-content: space-between; + font-family: var(--bl-display); + font-size: 1.1rem; +} + +.title-text { color: var(--bl-green); letter-spacing: 0.05em; } +.title-ver { color: var(--bl-text-dim); font-size: 0.9rem; } +.title-skull { color: var(--bl-red); } + +/* Window panels - chunky 3D inset */ +.win-panel { + margin: 0.5rem; + border: 3px solid var(--bl-border-light); + border-style: inset; + background: var(--bl-bg-inner); + box-shadow: inset 2px 2px 4px rgba(0, 0, 0, 0.5); +} + +.panel-title { + background: linear-gradient(90deg, var(--bl-red-dim), #1a1010); + color: var(--bl-green); + font-family: var(--bl-display); + font-size: 1rem; + padding: 0.3rem 0.75rem; + border-bottom: 1px solid var(--bl-border-dark); +} + +.panel-inner { padding: 1rem; } + +/* Header */ +header.win-panel .panel-inner { text-align: center; } + +header h1 { + font-family: var(--bl-display); + font-size: 2.5rem; + font-weight: 400; +} + +.bl-red { color: var(--bl-red); } +.bl-green { color: var(--bl-green); } +.bl-skull { color: var(--bl-red); } + +.tagline { color: var(--bl-text-dim); font-size: 0.95rem; margin: 0.2rem 0; } +.tagline.sub { font-style: italic; } + +.header-buttons { margin-top: 0.75rem; } +.header-buttons .bl-btn { margin: 0 0.25rem; } + +/* Nav */ +.nav-panel .panel-inner { + display: flex; + flex-wrap: wrap; + gap: 0.5rem; + justify-content: center; +} + +.nav-link { + color: var(--bl-text-dim); + padding: 0.25rem 0.5rem; +} + +.nav-link:hover { color: var(--bl-green); } + +/* Meter / stats bar */ +.meter-panel .panel-inner { + display: flex; + align-items: center; + gap: 0.5rem; + font-family: var(--bl-mono); +} + +.meter-date { color: var(--bl-text-dim); font-size: 0.9rem; } + +/* Bl box - info panels */ +.bl-box { + border: 2px solid var(--bl-border-light); + border-style: inset; + padding: 0.75rem; + margin: 1rem 0; + background: rgba(0, 0, 0, 0.3); +} + +.box-title { + color: var(--bl-red); + font-size: 0.9rem; + margin-bottom: 0.5rem; +} + +.bl-big { color: var(--bl-green); font-size: 1.05rem; margin-bottom: 0.5rem; } + +.bl-list { margin: 0.5rem 0 0 1rem; } +.bl-list li { margin: 0.25rem 0; } + +.bl-code { + background: #000; + padding: 0.1rem 0.3rem; + color: var(--bl-green); +} + +.bl-code.small { font-size: 0.75rem; word-break: break-all; } + +.bl-note { font-size: 0.8rem; color: var(--bl-text-dim); margin-top: 0.5rem; } + +.bl-label { color: var(--bl-text-dim); } + +/* Two column layout */ +.two-col { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 0.5rem; +} + +@media (max-width: 560px) { + .two-col { grid-template-columns: 1fr; } +} + +/* Link list */ +.bl-link-list { list-style: none; } +.bl-link-list li { margin: 0.4rem 0; } + +.bl-link { + display: block; + padding: 0.4rem; + border: 1px solid transparent; + color: var(--bl-green); + background: transparent; + font-family: inherit; + font-size: inherit; + cursor: pointer; + text-align: left; + width: 100%; +} + +.bl-link:hover { background: rgba(0, 204, 102, 0.1); } +.bl-link.danger { color: var(--bl-red); } +.bl-link.danger:hover { background: rgba(204, 51, 51, 0.1); } + +.contact-row { margin: 0.35rem 0; font-size: 0.9rem; } + +/* Services grid - from renderServicesForUGH */ +.services-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); + gap: 0.5rem; +} + +.service-group { + border: 2px solid var(--bl-border-light); + border-style: inset; + padding: 0.6rem; + background: rgba(0, 0, 0, 0.2); +} + +.service-group:hover { border-color: var(--bl-green-dim); } + +.service-group h3 { + font-size: 0.85rem; + color: var(--bl-green); + margin-bottom: 0.4rem; +} + +.service-group ul li { margin: 0.2rem 0; font-size: 0.85rem; } +.service-group a { color: var(--bl-text); } +.service-group a:hover { color: var(--bl-green); } +.service-group .alt { color: var(--bl-text-dim); font-size: 0.8rem; } + +/* Donate */ +.donate-col { text-align: center; } +.donate-col .bl-btn { margin: 0.25rem; display: inline-block; } + +.crypto-row { margin: 0.5rem 0; text-align: left; font-size: 0.85rem; } + +/* Bl button - 3D raised */ +.bl-btn { + background: linear-gradient(180deg, #2a2525 0%, #1a1616 100%); + border: 2px solid var(--bl-border-light); + border-style: outset; + color: var(--bl-green); + font-family: inherit; + font-size: 0.9rem; + padding: 0.35rem 0.75rem; + cursor: pointer; +} + +.bl-btn:hover { + background: linear-gradient(180deg, #1a1616 0%, #2a2525 100%); + border-style: inset; +} + +/* Links wrap */ +.links-wrap { + display: flex; + flex-wrap: wrap; + gap: 0.4rem; +} + +.bl-chip { + padding: 0.25rem 0.5rem; + border: 1px solid var(--bl-border-light); + color: var(--bl-text); + font-size: 0.85rem; +} + +.bl-chip:hover { + border-color: var(--bl-green); + color: var(--bl-green); +} + +/* Footer */ +.footer-panel .panel-inner { + text-align: center; + font-size: 0.9rem; + color: var(--bl-text-dim); +} + diff --git a/httpserver/data/ugh-bloodlust.html b/httpserver/data/ugh-bloodlust.html new file mode 100644 index 0000000..0bdc9df --- /dev/null +++ b/httpserver/data/ugh-bloodlust.html @@ -0,0 +1,172 @@ + + + + + + + UGH.im — Bloodlust Edition + + + + + + + + +
+
+ + + +
+
+ + UGH.im — BLOODLUST EDITION + v0.42 + +
+ +
+
+

UGH.im

+

Self-hosting is killing corporate profits.

+

We left these services open so you can help.

+
+ + +
+
+
+ + + +
+
+
+ Loading... +
+
+ +
+
ABOUT THIS SPACE
+
+

An experiment in self-hosting, data archiving, and community building!

+

Most services here are open to new users and connected with the Fediverse. All services run on home infrastructure and a cheap VPS.

+
+
[!] BANNED EXTENSIONS
+

These browser extensions have been BANNED by Google for causing problems for surveillance capitalism:

+ +
+
+
+ +
+
+
COMMUNITY
+ +
+ +
+
CONTACT
+
+ +
Signal: Gravitas.75
+ +
Email: GravityWell@RiseUp.net
+ +
+
+
+ +
+
SERVICES
+
+
+
[!] GUEST ACCESS
+

USER: gwguest   PASS: gravitywell.xyz

+

* GravityWell.xYz = home server | ugh.im = VPS

+
+
+
+
+ + + + + +
+ +
+
+ 2026 UGH.im — Thanks for visiting +
+
+
+ + + + + + + diff --git a/httpserver/data/ugh-bloodlust.js b/httpserver/data/ugh-bloodlust.js new file mode 100644 index 0000000..1a94292 --- /dev/null +++ b/httpserver/data/ugh-bloodlust.js @@ -0,0 +1,54 @@ +/** + * UGH.im — Bloodlust Edition + * Minimal interactions: date, theme, music + */ + +const CONFIG = { + musicVolume: 0.4, + skins: [ + { bg: "#0a0808", green: "#00cc66", red: "#cc3333" }, + { bg: "#080a08", green: "#66ff66", red: "#ff4444" }, + { bg: "#08080a", green: "#6666ff", red: "#ff6666" }, + { bg: "#0a080a", green: "#cc66cc", red: "#ff66aa" } + ] +}; + +/* Discordian Date */ +const fetchDiscordianDate = async () => { + try { + const r = await fetch("./ddate-now"); + const text = await r.text(); + document.getElementById("ddate").textContent = text.trim(); + } catch { + document.getElementById("ddate").textContent = "Welcome to UGH.im"; + } +}; +fetchDiscordianDate(); + +/* Theme / skin changer */ +let skinIndex = 0; +window.changeTheme = () => { + skinIndex = (skinIndex + 1) % CONFIG.skins.length; + const s = CONFIG.skins[skinIndex]; + document.documentElement.style.setProperty("--bl-bg", s.bg); + document.documentElement.style.setProperty("--bl-green", s.green); + document.documentElement.style.setProperty("--bl-red", s.red); +}; + +/* Music */ +const bgMusic = document.getElementById("bg-music"); +let musicOn = false; +window.toggleMusic = () => { + const btn = document.querySelector('button[onclick="toggleMusic()"]'); + if (musicOn) { + bgMusic.pause(); + musicOn = false; + if (btn) btn.textContent = "[MUSIC]"; + } else { + bgMusic.volume = CONFIG.musicVolume; + bgMusic.play() + .then(() => { musicOn = true; if (btn) btn.textContent = "[STOP]"; }) + .catch(() => { if (btn) btn.textContent = "[MUSIC]"; }); + } +}; + diff --git a/httpserver/data/ugh.css b/httpserver/data/ugh.css new file mode 100755 index 0000000..c2d25a8 --- /dev/null +++ b/httpserver/data/ugh.css @@ -0,0 +1,634 @@ +/** + * UGH.im — Modern Dark Theme + * Clean, contemporary design with bold accents + */ + +/* ========================================================================== + CSS Custom Properties + ========================================================================== */ + +:root { + --bg-primary: #0c0c0c; + --bg-secondary: #141414; + --bg-elevated: #1a1a1a; + --bg-card: rgba(26, 26, 26, 0.8); + --text-primary: #fafafa; + --text-secondary: #d4d4d4; + --text-muted: #a3a3a3; + --accent: #f43f5e; + --accent-hover: #fb7185; + --accent-dim: rgba(244, 63, 94, 0.15); + --border: rgba(255, 255, 255, 0.08); + --border-focus: rgba(244, 63, 94, 0.5); + --font-sans: "DM Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; + --font-mono: ui-monospace, SFMono-Regular, "Cascadia Code", "Fira Code", monospace; + --radius: 12px; + --radius-sm: 8px; + --shadow: 0 4px 24px rgba(0, 0, 0, 0.4); + --transition: 0.2s ease; +} + +/* ========================================================================== + Base + ========================================================================== */ + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +html { + scroll-behavior: smooth; +} + +body { + background: var(--bg-primary); + background-image: + radial-gradient(ellipse 80% 50% at 50% -20%, rgba(244, 63, 94, 0.12), transparent), + radial-gradient(ellipse 60% 40% at 100% 100%, rgba(244, 63, 94, 0.06), transparent); + color: var(--text-secondary); + font-family: var(--font-sans); + font-size: 1rem; + line-height: 1.6; + min-height: 100vh; +} + +::selection { + background: var(--accent); + color: white; +} + +a { + color: var(--accent); + text-decoration: none; + transition: color var(--transition); +} + +a:hover { + color: var(--accent-hover); +} + +ul { + list-style: none; +} + +/* ========================================================================== + Background + ========================================================================== */ + +#stars-bg { + position: fixed; + top: 0; + left: 0; + z-index: -2; + pointer-events: none; +} + +/* ========================================================================== + Container + ========================================================================== */ + +.container { + max-width: 720px; + margin: 0 auto; + padding: 1.5rem; +} + +/* ========================================================================== + Header + ========================================================================== */ + +header { + text-align: center; + padding: 2rem 0 1.5rem; + border-bottom: 1px solid var(--border); +} + +.header-sparkle { + font-size: 1.25rem; + margin-bottom: 0.5rem; + opacity: 0.8; +} + +h1 { + font-size: 2.5rem; + font-weight: 700; + letter-spacing: -0.02em; + color: var(--text-primary); + margin: 0.5rem 0 0.75rem; +} + +h1 .glow { + color: var(--accent); +} + +h1 .blink { + color: var(--text-muted); +} + +header>br+br+.header-buttons { + margin-top: 1rem; +} + +header p { + font-size: 0.95rem; + color: var(--text-muted); + max-width: 32rem; + margin: 0 auto; +} + +.header-buttons { + display: flex; + gap: 0.75rem; + justify-content: center; + flex-wrap: wrap; + margin-top: 1rem; +} + +.retro-btn { + background: var(--bg-elevated); + border: 1px solid var(--border); + color: var(--text-primary); + font-family: inherit; + font-size: 0.875rem; + font-weight: 500; + padding: 0.5rem 1rem; + border-radius: var(--radius-sm); + cursor: pointer; + transition: background var(--transition), border-color var(--transition); +} + +.retro-btn:hover { + background: var(--accent-dim); + border-color: var(--border-focus); +} + +/* ========================================================================== + Navigation + ========================================================================== */ + +nav { + position: sticky; + top: 0; + z-index: 100; + background: rgba(12, 12, 12, 0.9); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + border-bottom: 1px solid var(--border); + padding: 0.5rem 0; +} + +nav ul { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 0.25rem; +} + +.nav-link { + display: block; + padding: 0.5rem 1rem; + font-size: 0.875rem; + font-weight: 500; + color: var(--text-muted); + border-radius: var(--radius-sm); + transition: color var(--transition), background var(--transition); +} + +.nav-link:hover { + color: var(--accent); + background: var(--accent-dim); +} + +/* ========================================================================== + Main + ========================================================================== */ + +main { + padding: 1.5rem 0; +} + +/* ========================================================================== + Date + ========================================================================== */ + +.date-box { + background: var(--bg-elevated); + border: 1px solid var(--border); + border-radius: var(--radius-sm); + padding: 0.75rem 1rem; + text-align: center; + font-size: 0.9rem; + color: var(--text-muted); + margin-bottom: 1.5rem; +} + +/* ========================================================================== + Sections + ========================================================================== */ + +.section-box { + background: var(--bg-card); + border: 1px solid var(--border); + border-radius: var(--radius); + padding: 1.5rem; + margin-bottom: 1.5rem; +} + +.section-box.full-width { + width: 100%; +} + +h2 { + font-size: 1.25rem; + font-weight: 600; + color: var(--text-primary); + margin-bottom: 1rem; +} + +h2 .rainbow { + color: var(--accent); +} + +h3 { + font-size: 1rem; + font-weight: 600; + color: var(--text-primary); + margin-bottom: 0.75rem; +} + +.big-text { + font-size: 1.1rem; + color: var(--text-primary); + font-weight: 500; +} + +.highlight { + color: var(--accent); +} + +/* ========================================================================== + Layout + ========================================================================== */ + +.two-column { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 1.5rem; +} + +@media (max-width: 640px) { + .two-column { + grid-template-columns: 1fr; + } +} + +/* ========================================================================== + Info Box + ========================================================================== */ + +.info-box { + background: var(--accent-dim); + border: 1px solid var(--border-focus); + border-radius: var(--radius-sm); + padding: 1rem; + margin-top: 1rem; +} + +.cool-list { + padding-left: 1rem; + margin-top: 0.5rem; +} + +.cool-list li { + margin: 0.5rem 0; +} + +.cool-list li::before { + content: "→ "; + color: var(--accent); +} + +/* ========================================================================== + Links + ========================================================================== */ + +.link-list li, +.contact-list li { + margin: 0.5rem 0; +} + +.friend-link { + display: flex; + align-items: center; + gap: 0.75rem; + padding: 0.75rem 1rem; + background: var(--bg-elevated); + border: 1px solid var(--border); + border-radius: var(--radius-sm); + transition: border-color var(--transition), background var(--transition); +} + +.friend-link:hover { + background: var(--accent-dim); + border-color: var(--border-focus); +} + +.friend-link .icon { + font-size: 1.25rem; +} + +.contact-list .label { + font-size: 0.75rem; + text-transform: uppercase; + letter-spacing: 0.05em; + color: var(--text-muted); +} + +/* ========================================================================== + Guest Box + ========================================================================== */ + +.guest-box { + background: var(--bg-elevated); + border: 1px solid var(--border); + border-radius: var(--radius); + padding: 1.25rem; + margin-bottom: 1.5rem; + text-align: center; +} + +.credentials { + background: var(--bg-primary); + border: 1px solid var(--border); + border-radius: var(--radius-sm); + padding: 1rem; + margin: 1rem auto; + max-width: 280px; + font-family: var(--font-mono); + font-size: 0.875rem; +} + +.cred-label { + color: var(--text-muted); +} + +.cred-value { + color: var(--accent); +} + +.note { + font-size: 0.8rem; + color: var(--text-muted); + margin-top: 0.75rem; +} + +/* ========================================================================== + Services Grid + ========================================================================== */ + +.services-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); + gap: 1rem; +} + +.service-group { + background: var(--bg-elevated); + border: 1px solid var(--border); + border-radius: var(--radius); + padding: 1rem; + transition: border-color var(--transition), box-shadow var(--transition); +} + +.service-group:hover { + border-color: var(--border-focus); + box-shadow: var(--shadow); +} + +.service-group h3 { + font-size: 0.9rem; + margin-bottom: 0.5rem; +} + +.service-group ul li { + margin: 0.35rem 0; + font-size: 0.9rem; +} + +.service-group a { + color: inherit; +} + +.service-group a:hover { + color: var(--accent); +} + +.register, +.alt { + font-size: 0.8rem; + margin-left: 0.25rem; +} + +.alt { + color: var(--text-muted); +} + +/* Maintenance Status */ +.status-maintenance { + opacity: 0.5; + filter: grayscale(1); + pointer-events: none; +} + +/* Back-compat: treat "down" the same as prior "maintenance" */ +.status-down { + opacity: 0.5; + filter: grayscale(1); + pointer-events: none; +} + +.status-maintenance a { + cursor: not-allowed; + text-decoration: line-through !important; +} + +.status-down a { + cursor: not-allowed; + text-decoration: line-through !important; +} + +.maintenance-badge { + font-size: 0.7rem; + color: var(--accent); + margin-left: 0.5rem; + font-weight: bold; + text-transform: uppercase; +} + +/* ========================================================================== + Donate + ========================================================================== */ + +.donate-box { + text-align: center; +} + +.donate-list { + display: flex; + flex-wrap: wrap; + gap: 0.5rem; + justify-content: center; + margin-top: 0.5rem; +} + +.donate-link { + display: inline-block; + padding: 0.5rem 1rem; + background: var(--bg-elevated); + border: 1px solid var(--border); + border-radius: var(--radius-sm); + font-weight: 500; + font-size: 0.9rem; + margin: 0.25rem; + transition: background var(--transition), border-color var(--transition); +} + +.donate-link:hover { + background: var(--accent-dim); + border-color: var(--border-focus); +} + +.crypto-item { + margin: 0.75rem 0; + text-align: left; +} + +.crypto-name { + font-size: 0.8rem; + color: var(--text-muted); +} + +.crypto-addr { + display: block; + background: var(--bg-primary); + border: 1px solid var(--border); + border-radius: 4px; + padding: 0.5rem; + font-size: 0.7rem; + font-family: var(--font-mono); + word-break: break-all; + margin-top: 0.25rem; + color: var(--text-secondary); +} + +/* ========================================================================== + Awesome Links + ========================================================================== */ + +.links-grid { + display: flex; + flex-wrap: wrap; + gap: 0.5rem; + justify-content: center; +} + +.awesome-link { + padding: 0.4rem 0.75rem; + background: var(--bg-elevated); + border: 1px solid var(--border); + border-radius: 6px; + font-size: 0.875rem; + color: var(--text-secondary); + transition: background var(--transition), border-color var(--transition); +} + +.awesome-link:hover { + background: var(--accent-dim); + border-color: var(--border-focus); + color: var(--accent); +} + +/* ========================================================================== + Footer + ========================================================================== */ + +footer { + border-top: 1px solid var(--border); + padding: 2rem 0; + text-align: center; +} + +.footer-decor { + font-size: 1rem; + opacity: 0.6; + margin-bottom: 0.5rem; +} + +.footer-text { + font-size: 0.875rem; + color: var(--text-muted); +} + +.footer-buttons { + margin-top: 1rem; +} + +.footer-buttons img { + display: none; +} + +.badge { + display: inline-block; + padding: 0.25rem 0.5rem; + background: var(--bg-elevated); + border: 1px solid var(--border); + border-radius: 4px; + font-size: 0.7rem; + color: var(--text-muted); +} + +/* ========================================================================== + Scrollbar + ========================================================================== */ + +::-webkit-scrollbar { + width: 10px; + height: 10px; +} + +::-webkit-scrollbar-track { + background: var(--bg-primary); +} + +::-webkit-scrollbar-thumb { + background: var(--bg-elevated); + border-radius: 5px; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--text-muted); +} + +/* ========================================================================== + Responsive + ========================================================================== */ + +@media (max-width: 480px) { + .container { + padding: 1rem; + } + + h1 { + font-size: 2rem; + } + + nav ul { + flex-direction: column; + } + + .services-grid { + grid-template-columns: 1fr; + } +} \ No newline at end of file diff --git a/httpserver/data/ugh.html b/httpserver/data/ugh.html new file mode 100644 index 0000000..f8dbcc7 --- /dev/null +++ b/httpserver/data/ugh.html @@ -0,0 +1,263 @@ + + + + + + + UGH.im — Self-Hosting + + + + + + + + + + + + + +
+ +
+
🔥 😈 💀
+

+ UGH.im +

+

Self-hosting is killing corporate profits. We left these services open so you can help.

+
+ + +
+
+ + + + + +
+
Loading date...
+ +
+

About This Space

+
+

An experiment in self-hosting, data archiving, and community building!

+

Most services here are open to new users and connected with the Fediverse. All services are running on home infrastructure and a + cheap VPS.

+ +
+

Try These Banned Extensions

+

These browser extensions have been BANNED by Google for causing problems for + surveillance capitalism!

+ +
+
+
+ + +
+
+

Community

+ +
+ +
+

Contact

+ +
+
+ + +
+

Services

+ +
+

Guest Access

+

Some services don't have a sign-up option. Use the guest account to try them out:

+
+

USER: gwguest

+

PASS: gravitywell.xyz

+
+

* GravityWell.xYz = home server | ugh.im = VPS

+
+ +
+ +
+
+ + + + +
+ + +
+ + + + + + + + \ No newline at end of file diff --git a/httpserver/data/ugh.js b/httpserver/data/ugh.js new file mode 100755 index 0000000..330575b --- /dev/null +++ b/httpserver/data/ugh.js @@ -0,0 +1,126 @@ +/** + * UGH.im — Modern theme interactions + */ + +const CONFIG = { + particleCount: 80, + musicVolume: 0.4, + themes: [ + { bg: "#0c0c0c", accent: "#f43f5e", hover: "#fb7185" }, + { bg: "#0a0f14", accent: "#38bdf8", hover: "#7dd3fc" }, + { bg: "#0d1117", accent: "#7ee787", hover: "#bbf7d0" }, + { bg: "#0f0a14", accent: "#a78bfa", hover: "#c4b5fd" }, + { bg: "#140a0a", accent: "#f87171", hover: "#fca5a5" } + ] +}; + +/* ========================================================================== + Discordian Date + ========================================================================== */ + +const fetchDiscordianDate = async () => { + try { + const response = await fetch("./ddate-now"); + const date = await response.text(); + document.getElementById("ddate").textContent = date.trim(); + } catch { + document.getElementById("ddate").textContent = "Welcome to UGH.im"; + } +}; + +fetchDiscordianDate(); + +/* ========================================================================== + Ambient Particles (subtle) + ========================================================================== */ + +const canvas = document.getElementById("stars-bg"); +if (canvas) { + const ctx = canvas.getContext("2d"); + let width, height; + const particles = []; + + const resize = () => { + width = canvas.width = window.innerWidth; + height = canvas.height = window.innerHeight; + }; + + class Particle { + constructor() { + this.reset(); + } + reset() { + this.x = Math.random() * width; + this.y = Math.random() * height; + this.size = Math.random() * 1.5 + 0.5; + this.speed = Math.random() * 0.3 + 0.05; + this.opacity = Math.random() * 0.4 + 0.1; + } + update() { + this.y += this.speed; + if (this.y > height) this.y = 0; + } + draw() { + ctx.beginPath(); + ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2); + ctx.fillStyle = `rgba(244, 63, 94, ${this.opacity})`; + ctx.fill(); + } + } + + resize(); + for (let i = 0; i < CONFIG.particleCount; i++) particles.push(new Particle()); + + const animate = () => { + ctx.fillStyle = "rgba(12, 12, 12, 0.15)"; + ctx.fillRect(0, 0, width, height); + particles.forEach(p => { + p.update(); + p.draw(); + }); + requestAnimationFrame(animate); + }; + animate(); + window.addEventListener("resize", resize); +} + +/* ========================================================================== + Theme Changer + ========================================================================== */ + +let themeIndex = 0; + +window.changeTheme = () => { + themeIndex = (themeIndex + 1) % CONFIG.themes.length; + const t = CONFIG.themes[themeIndex]; + document.documentElement.style.setProperty("--bg-primary", t.bg); + document.documentElement.style.setProperty("--accent", t.accent); + document.documentElement.style.setProperty("--accent-hover", t.hover); +}; + +/* ========================================================================== + Music + ========================================================================== */ + +const bgMusic = document.getElementById("bg-music"); +let musicPlaying = false; + +window.toggleMusic = () => { + const btn = document.querySelector('button[onclick="toggleMusic()"]'); + if (musicPlaying) { + bgMusic.pause(); + musicPlaying = false; + if (btn) btn.textContent = "🎵 Play Music"; + } else { + bgMusic.volume = CONFIG.musicVolume; + bgMusic.play() + .then(() => { + musicPlaying = true; + if (btn) btn.textContent = "🔇 Stop Music"; + }) + .catch(() => { + if (btn) btn.textContent = "🎵 Play Music"; + }); + } +}; + diff --git a/httpserver/data/vaporwave.css b/httpserver/data/vaporwave.css new file mode 100644 index 0000000..03cf05d --- /dev/null +++ b/httpserver/data/vaporwave.css @@ -0,0 +1,295 @@ +/** + * Vaporwave Variety — 1999 GeoCities Aesthetic + * Colors: Pink #ff71ce, Cyan #01cdfe, Purple #b967ff, Neon Green #05ffa1 + */ + +:root { + --pink: #ff71ce; + --cyan: #01cdfe; + --purple: #b967ff; + --green: #05ffa1; + --bg-dark: #24142c; + --bg-darker: #1a0b1f; + + --text-main: #fafafa; + --font-sans: 'DM Sans', sans-serif; + --font-mono: ui-monospace, SFMono-Regular, "Cascadia Code", "Fira Code", monospace; +} + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + background-color: var(--bg-dark); + background-image: + linear-gradient(var(--bg-darker) 1px, transparent 1px), + linear-gradient(90deg, var(--bg-darker) 1px, transparent 1px); + background-size: 40px 40px; + color: var(--text-main); + font-family: var(--font-sans); + line-height: 1.4; + overflow-x: hidden; +} + +/* Scanline Effect */ +body::before { + content: " "; + display: block; + position: fixed; + top: 0; + left: 0; + bottom: 0; + right: 0; + background: linear-gradient(rgba(18, 16, 16, 0) 50%, rgba(0, 0, 0, 0.25) 50%), linear-gradient(90deg, rgba(255, 0, 0, 0.06), rgba(0, 255, 0, 0.02), rgba(0, 0, 255, 0.06)); + z-index: 1000; + background-size: 100% 2px, 3px 100%; + pointer-events: none; +} + +.container { + max-width: 800px; + margin: 0 auto; + padding: 20px; + background: rgba(36, 20, 44, 0.85); + border: 4px ridge var(--purple); + box-shadow: 10px 10px 0px var(--cyan); +} + +/* Header & WordArt */ +header { + text-align: center; + padding: 40px 10px; + border-bottom: 2px dashed var(--cyan); + margin-bottom: 30px; +} + +.wordart { + font-family: 'Impact', sans-serif; + font-size: 4rem; + font-weight: bold; + letter-spacing: 2px; + display: inline-block; + margin: 20px 0; + -webkit-text-stroke: 1px var(--text-main); +} + +.wordart-vapor { + background: linear-gradient(to bottom, var(--pink) 0%, var(--purple) 50%, var(--cyan) 100%); + -webkit-background-clip: text; + background-clip: text; + color: transparent; + transform: skewY(-5deg) scaleY(1.2); + filter: drop-shadow(4px 4px 0px rgba(1, 205, 254, 0.8)); +} + +.sub-title { + font-size: 1.2rem; + color: var(--green); + font-family: var(--font-mono); + margin-top: 10px; + text-shadow: 2px 2px var(--bg-darker); +} + +/* Marquee */ +.marquee-container { + background: var(--bg-darker); + border: 2px solid var(--pink); + margin: 20px 0; + padding: 5px; + overflow: hidden; + white-space: nowrap; +} + +.marquee-content { + display: inline-block; + padding-left: 100%; + animation: marquee 20s linear infinite; + color: var(--cyan); + font-weight: bold; + font-family: var(--font-mono); + text-transform: uppercase; +} + +@keyframes marquee { + 0% { transform: translate(0, 0); } + 100% { transform: translate(-100%, 0); } +} + +/* Navigation */ +nav { + margin-bottom: 30px; +} + +nav ul { + list-style: none; + display: flex; + justify-content: center; + gap: 10px; + flex-wrap: wrap; +} + +.nav-link { + display: block; + padding: 8px 15px; + background: var(--bg-darker); + border: 2px solid var(--purple); + color: var(--pink); + text-decoration: none; + font-weight: bold; + transition: all 0.2s; +} + +.nav-link:hover { + background: var(--pink); + color: var(--bg-darker); + transform: translate(-3px, -3px); + box-shadow: 3px 3px 0px var(--cyan); +} + +/* Sections */ +section { + margin-bottom: 40px; + border: 2px solid var(--cyan); + padding: 20px; + position: relative; +} + +section h2 { + font-size: 1.5rem; + background: var(--cyan); + color: var(--bg-darker); + display: inline-block; + padding: 5px 15px; + position: absolute; + top: -15px; + left: 15px; + text-transform: uppercase; +} + +/* Boxes and Lists */ +.info-box { + background: rgba(185, 103, 255, 0.1); + border: 2px dashed var(--green); + padding: 15px; + margin-top: 20px; +} + +.highlight { + color: var(--pink); + font-weight: bold; +} + +.cool-list { + list-style: none; + margin-top: 15px; +} + +.cool-list li { + margin: 10px 0; +} + +.cool-list li a { + color: var(--cyan); + text-decoration: underline; +} + +.cool-list li a:hover { + color: var(--green); + background: var(--bg-darker); +} + +/* Two Column Grid */ +.grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 20px; +} + +@media (max-width: 600px) { + .grid { + grid-template-columns: 1fr; + } +} + +/* Services Dynamic Content */ +#services-container { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 15px; + margin-top: 10px; +} + +.service-group { + border: 1px solid var(--purple); + background: var(--bg-darker); + padding: 10px; +} + +.service-group h3 { + color: var(--green); + border-bottom: 1px solid var(--purple); + margin-bottom: 8px; + font-size: 0.9rem; +} + +.service-group ul { + list-style: none; +} + +.service-group li { + font-size: 0.85rem; + margin: 4px 0; +} + +.service-group a { + color: var(--cyan); + text-decoration: none; +} + +.service-group a:hover { + text-decoration: underline; + color: var(--pink); +} + +/* Badges */ +.badge-container { + text-align: center; + margin: 20px 0; +} + +.badge { + image-rendering: pixelated; + margin: 5px; +} + +/* Footer */ +footer { + text-align: center; + padding: 30px 0; + border-top: 2px dashed var(--purple); + font-size: 0.8rem; + color: var(--purple); +} + +footer a { + color: var(--cyan); +} + +/* Utility */ +.blink { + animation: blink 1s step-end infinite; +} + +@keyframes blink { + 50% { opacity: 0; } +} + +.rainbow-text { + background: linear-gradient(to right, red, orange, yellow, green, blue, indigo, violet); + -webkit-background-clip: text; + background-clip: text; + color: transparent; +} diff --git a/httpserver/data/vaporwave.html b/httpserver/data/vaporwave.html new file mode 100644 index 0000000..8b41ddf --- /dev/null +++ b/httpserver/data/vaporwave.html @@ -0,0 +1,158 @@ + + + + + + + UGH // GRAVITYWELL — Vaporwave Edition + + + + + + + + + +
+ +
+
+

UGH.im

+
+
~ GRAVITYWELL.xYz ~
+ +
+ + +
+
+ Self-hosting is killing corporate profits. We left these services open so you can help. --- DATA ARCHIVING --- COMMUNITY BUILDING --- SURVEILLANCE CAPITALISM IS A BUG --- +
+
+ + + + + +
+
+ [ LOADING SYSTEM DATE... ] +
+ +
+

About

+

An experiment in self-hosting, data archiving, and community building!

+

Most services here are open to new users and connected with the Fediverse. All services are running on home infrastructure and a cheap VPS.

+ +
+

[ ! ] Try These Banned Extensions

+

These browser extensions have been BANNED by Google for causing problems for surveillance capitalism!

+ +
+
+ +
+
+

Community

+ +
+ +
+

Contact

+ +
+
+ +
+

Services

+
+

Guest Access

+

Some services don't have a sign-up option. Use the guest account:

+
+

USER: gwguest

+

PASS: gravitywell.xyz

+
+
+
+ +
+
+ + + +
+ email me + neocities + fsf +
+
+ +
+

© 2026 UGH.im & GravityWell.xYz

+

VAPORWAVE EDITION // PROCESSED IN 640x480

+

RETURN TO MAIN

+
+
+ + + + + + diff --git a/index.html b/index.html new file mode 100644 index 0000000..5c07a98 --- /dev/null +++ b/index.html @@ -0,0 +1,286 @@ + + + + + + Service Directory + + + +
+
+

Service Directory

+
+ +
+

Media & Entertainment

+
+
+ Jellyfin +

The volunteer-built media solution.

+ gw.ugh.im +
+
+ Piped +

Privacy-focused YouTube frontend.

+ piped.gravitywell.xyz +
+
+ PeerTube +

Federated video hosting platform.

+ peertube.gravitywell.xyz +
+
+ Navidrome +

Modern self-hosted music server and streamer.

+ navi.gravitywell.xyz +
+
+ Feishin +

Modern music player for Navidrome/Subsonic.

+ feishin.gravitywell.xyz +
+
+ RomM +

Game library manager for ROMs.

+ romm.gravitywell.xyz +
+
+ Stash +

Organize, network, and celebrate your adult content.

+ stash.gravitywell.xyz +
+
+ Soulseek +

Web-based Soulseek client.

+ slsk.gravitywell.xyz +
+
+ Jellystat +

Statistics for your Jellyfin server.

+ jstat.gravitywell.xyz +
+
+
+ +
+

Social & Communication

+
+
+ Lemmy +

Federated link aggregator (Reddit alternative).

+ lem.ugh.im +
+
+ Discourse +

Modern community discussion platform.

+ forum.gravitywell.xyz +
+
+ Rocket.Chat +

The open-source communications platform.

+ rocketchat.gravitywell.xyz +
+
+ Jitsi Meet +

Secure, fully featured video conferencing.

+ meet.gravitywell.xyz +
+
+ NoStrudel +

Powerful web client for Nostr.

+ nostrudel.gravitywell.xyz +
+
+ Primal +

Fast and feature-rich Nostr web client.

+ primal.gravitywell.xyz +
+
+ Akkoma +

Federated microblogging platform.

+ akkoma.gravitywell.xyz +
+
+ Movim +

Decentralized social platform based on XMPP.

+ movim.gravitywell.xyz +
+
+ Enigma BBS +

Modern BBS software (BBS.ugh.im).

+ bbs.ugh.im +
+
+
+ +
+

Privacy Proxies

+
+
+ SearXNG +

Privacy-respecting metasearch engine.

+ searx.gravitywell.xyz +
+
+ Rimgo +

An alternative Imgur frontend.

+ rimgo.gravitywell.xyz +
+
+ Redlib +

Private Reddit frontend.

+ redlib.gravitywell.xyz +
+
+ Quetre +

Private Quora frontend.

+ qr.ugh.im +
+
+ ProxiTok +

Alternative TikTok frontend.

+ pt.ugh.im +
+
+
+ +
+

Productivity & Tools

+
+
+ Nextcloud +

Safe home for all your data.

+ cloud.gravitywell.xyz +
+
+ Vikunja +

The todo-app to organize your life.

+ tasks.gravitywell.xyz +
+
+ HedgeDoc +

Real-time collaborative markdown notes.

+ hd.ugh.im +
+
+ PrivateBin +

Minimalist, open source online pastebin.

+ pb.ugh.im +
+
+ Immich +

High performance self-hosted photo/video backup.

+ ch.ugh.im +
+
+ Uptime Kuma +

Self-hosted monitoring tool.

+ ut.ugh.im +
+
+ Speedtest +

Network performance testing.

+ speedtest.gravitywell.xyz +
+
+ LLM +

Large Language Model Interface.

+ llm.gravitywell.xyz +
+
+
+ +
+

System & Infrastructure

+
+
+ Grafana +

Observability and data visualization.

+ stats.gravitywell.xyz +
+
+ Dashboard +

Main landing and management portal.

+ gravitywell.xyz +
+
+
+ + +
+ + \ No newline at end of file diff --git a/services.yaml b/services.yaml new file mode 100644 index 0000000..c257e2f --- /dev/null +++ b/services.yaml @@ -0,0 +1,543 @@ +http: + routers: + gravitywell-xyz-router: + rule: "Host(`gravitywell.xyz`)" + service: "gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + gw-ugh-im-router: + rule: "Host(`gw.ugh.im`) || Host(`jellyfin.gravitywell.xyz`) || Host(`jfin.gravitywell.xyz`)" + service: "gw-ugh-im-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + lw-gravitywell-xyz-router: + rule: "Host(`lw.gravitywell.xyz`) || Host(`lw.ugh.im`)" + service: "lw-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + rimgo-gravitywell-xyz-router: + rule: "Host(`rimgo.gravitywell.xyz`)" + service: "rimgo-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + radarr-gravitywell-xyz-router: + rule: "Host(`radarr.gravitywell.xyz`)" + service: "radarr-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + searx-gravitywell-xyz-router: + rule: "Host(`searx.gravitywell.xyz`)" + service: "searx-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + lem-ugh-im-router: + rule: "Host(`lem.ugh.im`)" + service: "lem-ugh-im-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + wiz-gravitywell-xyz-router: + rule: "Host(`wiz.gravitywell.xyz`)" + service: "wiz-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + sonarr-gravitywell-xyz-router: + rule: "Host(`sonarr.gravitywell.xyz`)" + service: "sonarr-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + seerr-gravitywell-xyz-router: + rule: "Host(`seerr.gravitywell.xyz`)" + service: "seerr-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + speedtest-gravitywell-xyz-router: + rule: "Host(`speedtest.gravitywell.xyz`)" + service: "speedtest-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + piped-gravitywell-xyz-router: + rule: "Host(`piped.gravitywell.xyz`) || Host(`pipedapi.gravitywell.xyz`) || Host(`pipedproxy.gravitywell.xyz`)" + service: "piped-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + feishin-gravitywell-xyz-router: + rule: "Host(`feishin.gravitywell.xyz`)" + service: "feishin-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + m-gravitywell-xyz-router: + rule: "Host(`m.gravitywell.xyz`) || Host(`m.pl.ugh.im`) || Host(`pl.ugh.im`)" + service: "m-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + navi-gravitywell-xyz-router: + rule: "Host(`navi.gravitywell.xyz`) || Host(`nv.ugh.im`)" + service: "navi-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + redlib-gravitywell-xyz-router: + rule: "Host(`redlib.gravitywell.xyz`)" + service: "redlib-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + ugh-im-router: + rule: "Host(`ugh.im`)" + service: "ugh-im-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + mx-ugh-im-router: + rule: "Host(`mx.ugh.im`)" + service: "mx-ugh-im-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + st-ugh-im-router: + rule: "Host(`st.ugh.im`)" + service: "st-ugh-im-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + fr-ugh-im-router: + rule: "Host(`fr.ugh.im`)" + service: "fr-ugh-im-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + hd-ugh-im-router: + rule: "Host(`hd.ugh.im`) || Host(`hedge.gravitywell.xyz`)" + service: "hd-ugh-im-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + pb-ugh-im-router: + rule: "Host(`pb.ugh.im`) || Host(`privbin.gravitywell.xyz`)" + service: "pb-ugh-im-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + rd-ugh-im-router: + rule: "Host(`rd.ugh.im`)" + service: "rd-ugh-im-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + qr-ugh-im-router: + rule: "Host(`qr.ugh.im`) || Host(`quetre.gravitywell.xyz`)" + service: "qr-ugh-im-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + romm-gravitywell-xyz-router: + rule: "Host(`romm.gravitywell.xyz`)" + service: "romm-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + ch-ugh-im-router: + rule: "Host(`ch.ugh.im`)" + service: "ch-ugh-im-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + remote-override-ugh-im-router: + rule: "Host(`remote-override.ugh.im`)" + service: "remote-override-ugh-im-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + sw-ugh-im-router: + rule: "Host(`sw.ugh.im`)" + service: "sw-ugh-im-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + tasks-gravitywell-xyz-router: + rule: "Host(`tasks.gravitywell.xyz`)" + service: "tasks-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + peertube-gravitywell-xyz-router: + rule: "Host(`peertube.gravitywell.xyz`)" + service: "peertube-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + llm-gravitywell-xyz-router: + rule: "Host(`llm.gravitywell.xyz`)" + service: "llm-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + cloud-gravitywell-xyz-router: + rule: "Host(`cloud.gravitywell.xyz`) || Host(`nc.ugh.im`)" + service: "cloud-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + discourse-gravitywell-xyz-router: + rule: "Host(`discourse.gravitywell.xyz`) || Host(`forum.gravitywell.xyz`)" + service: "discourse-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + dumb-gravitywell-xyz-router: + rule: "Host(`dumb.gravitywell.xyz`)" + service: "dumb-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + proxitok-gravitywell-xyz-router: + rule: "Host(`proxitok.gravitywell.xyz`) || Host(`pt.ugh.im`)" + service: "proxitok-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + slsk-gravitywell-xyz-router: + rule: "Host(`slsk.gravitywell.xyz`)" + service: "slsk-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + pie-gravitywell-xyz-router: + rule: "Host(`pie.gravitywell.xyz`)" + service: "pie-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + gs-ugh-im-router: + rule: "Host(`gs.ugh.im`)" + service: "gs-ugh-im-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + jf-ugh-im-router: + rule: "Host(`jf.ugh.im`)" + service: "jf-ugh-im-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + grafana-gravitywell-xyz-router: + rule: "Host(`grafana.gravitywell.xyz`) || Host(`stats.gravitywell.xyz`)" + service: "grafana-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + jstat-gravitywell-xyz-router: + rule: "Host(`jstat.gravitywell.xyz`)" + service: "jstat-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + talk-gravitywell-xyz-router: + rule: "Host(`talk.gravitywell.xyz`)" + service: "talk-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + bs-ugh-im-router: + rule: "Host(`bs.ugh.im`) || Host(`stash.gravitywell.xyz`)" + service: "bs-ugh-im-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + jit-ugh-im-router: + rule: "Host(`jit.ugh.im`) || Host(`jitsi.gravitywell.xyz`) || Host(`meet.gravitywell.xyz`)" + service: "jit-ugh-im-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + mc-ugh-im-router: + rule: "Host(`mc.ugh.im`)" + service: "mc-ugh-im-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + kuma-gravitywell-xyz-router: + rule: "Host(`kuma.gravitywell.xyz`) || Host(`ut.ugh.im`)" + service: "kuma-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + floatilla-gravitywell-xyz-router: + rule: "Host(`floatilla.gravitywell.xyz`) || Host(`flt.ugh.im`)" + service: "floatilla-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + nostr-gravitywell-xyz-router: + rule: "Host(`nostr.gravitywell.xyz`)" + service: "nostr-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + nostrudel-gravitywell-xyz-router: + rule: "Host(`nostrudel.gravitywell.xyz`) || Host(`nsdl.ugh.im`)" + service: "nostrudel-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + primal-gravitywell-xyz-router: + rule: "Host(`primal.gravitywell.xyz`) || Host(`prml.ugh.im`)" + service: "primal-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + stoat-gravitywell-xyz-router: + rule: "Host(`stoat.gravitywell.xyz`)" + service: "stoat-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + rocketchat-gravitywell-xyz-router: + rule: "Host(`rocketchat.gravitywell.xyz`)" + service: "rocketchat-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + bbs-ugh-im-router: + rule: "Host(`bbs.ugh.im`) || Host(`enigma.gravitywell.xyz`)" + service: "bbs-ugh-im-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + spacebar-gravitywell-xyz-router: + rule: "Host(`spacebar.gravitywell.xyz`)" + service: "spacebar-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + searx-ugh-im-router: + rule: "Host(`searx.ugh.im`)" + service: "searx-ugh-im-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + fluxer-gravitywell-xyz-router: + rule: "Host(`fluxer.gravitywell.xyz`)" + service: "fluxer-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + test-gravitywell-xyz-router: + rule: "Host(`test.gravitywell.xyz`)" + service: "test-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + akkoma-gravitywell-xyz-router: + rule: "Host(`akkoma.gravitywell.xyz`)" + service: "akkoma-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + poke-gravitywell-xyz-router: + rule: "Host(`poke.gravitywell.xyz`)" + service: "poke-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + movim-gravitywell-xyz-router: + rule: "Host(`movim.gravitywell.xyz`)" + service: "movim-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + services: + gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:9797" + gw-ugh-im-service: + loadBalancer: + servers: + - url: "http://10.8.0.10:8096" + lw-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:3515" + rimgo-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.10:3492" + radarr-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.10:7878" + searx-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.10:8282" + lem-ugh-im-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:10633" + wiz-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.10:5690" + sonarr-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.10:8989" + seerr-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.10:5055" + speedtest-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.10:3300" + piped-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.20:8107" + feishin-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.10:9180" + m-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:29500" + navi-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.10:24533" + redlib-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.10:29501" + ugh-im-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:9798" + mx-ugh-im-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:6167" + st-ugh-im-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:13300" + fr-ugh-im-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:8281" + hd-ugh-im-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:3969" + pb-ugh-im-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:8956" + rd-ugh-im-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:29503" + qr-ugh-im-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:3629" + romm-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.10:17920" + ch-ugh-im-service: + loadBalancer: + servers: + - url: "http://10.8.0.2:2283" + remote-override-ugh-im-service: + loadBalancer: + servers: + - url: "http://aw2cd67.glddns.com:56599" + sw-ugh-im-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:3666" + tasks-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:3456" + peertube-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.10:29511" + llm-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.2:3235" + cloud-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.50:26145" + discourse-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.50:20080" + dumb-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:1485" + proxitok-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:14861" + slsk-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.10:5030" + pie-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.10:8030" + gs-ugh-im-service: + loadBalancer: + servers: + - url: "http://10.8.0.99:8096" + jf-ugh-im-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:8096" + grafana-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:3010" + jstat-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.10:3963" + talk-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:19683" + bs-ugh-im-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:5059" + jit-ugh-im-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:8297" + mc-ugh-im-service: + loadBalancer: + servers: + - url: "http://10.8.0.2:8922" + kuma-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:3259" + floatilla-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:3267" + nostr-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:3601" + nostrudel-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:8756" + primal-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:8757" + stoat-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.20:947" + rocketchat-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.50:3127" + bbs-ugh-im-service: + loadBalancer: + servers: + - url: "http://10.8.0.50:8915" + spacebar-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.20:8657" + searx-ugh-im-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:8282" + fluxer-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.20:9802" + test-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.50:9797" + akkoma-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.50:29500" + poke-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.50:6003" + movim-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.20:1692" diff --git a/traefik/certs/gravitywell.key b/traefik/certs/gravitywell.key new file mode 100644 index 0000000..aae1c13 --- /dev/null +++ b/traefik/certs/gravitywell.key @@ -0,0 +1,6 @@ +-----BEGIN PRIVATE KEY----- +MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDCGipe2wAuXf7EmcA0w +xk3R/PjqOYUwT6Ib6A/Iu6U03yk9jyYMk/CMS31LP3IZgIShZANiAARumT6tonE2 +LEs53R9hmiKv0qgmGVCXbHUk6Qip1k1yYP/IES0srj+ELKGhNlrsjn2qFX0wKG0b +6PDLrPbWC85h101wmIFkmz4dAAw8x20yE3ARRHzcfuIleNOt2AoVpvE= +-----END PRIVATE KEY----- diff --git a/traefik/certs/gravitywell.pem b/traefik/certs/gravitywell.pem new file mode 100644 index 0000000..dd160fb --- /dev/null +++ b/traefik/certs/gravitywell.pem @@ -0,0 +1,49 @@ +-----BEGIN CERTIFICATE----- +MIIDvTCCA0SgAwIBAgISBsWdMewVvkMG4E3g4J2n3u7HMAoGCCqGSM49BAMDMDIx +CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQDEwJF +ODAeFw0yNjAxMjMyMDA1MDJaFw0yNjA0MjMyMDA1MDFaMBwxGjAYBgNVBAMMESou +Z3Jhdml0eXdlbGwueHl6MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEbpk+raJxNixL +Od0fYZoir9KoJhlQl2x1JOkIqdZNcmD/yBEtLK4/hCyhoTZa7I59qhV9MChtG+jw +y6z21gvOYddNcJiBZJs+HQAMPMdtMhNwEUR83H7iJXjTrdgKFabxo4ICMTCCAi0w +DgYDVR0PAQH/BAQDAgeAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAM +BgNVHRMBAf8EAjAAMB0GA1UdDgQWBBQV5Aa63AxCB+FGV9yV7zhmnKx/lDAfBgNV +HSMEGDAWgBSPDROi9i5+0VBsMxg4XVmOI3KRyjAyBggrBgEFBQcBAQQmMCQwIgYI +KwYBBQUHMAKGFmh0dHA6Ly9lOC5pLmxlbmNyLm9yZy8wLQYDVR0RBCYwJIIRKi5n +cmF2aXR5d2VsbC54eXqCD2dyYXZpdHl3ZWxsLnh5ejATBgNVHSAEDDAKMAgGBmeB +DAECATAtBgNVHR8EJjAkMCKgIKAehhxodHRwOi8vZTguYy5sZW5jci5vcmcvNzIu +Y3JsMIIBBQYKKwYBBAHWeQIEAgSB9gSB8wDxAHYAZBHEbKQS7KeJHKICLgC8q08o +B9QeNSer6v7VA8l9zfAAAAGb7Ktd/gAABAMARzBFAiEAjp0O6ETSfTca3CBqD+rd +puaNFm6wRNoFCMtel2so5tkCIAd/aLMffxJxao++xuSXIPBGOAmMIA5flEyKT2G4 +WBFSAHcA0W6ppWgHfmY1oD83pd28A6U8QRIU1IgY9ekxsyPLlQQAAAGb7KtfAQAA +BAMASDBGAiEAtT7P2R0BqSHlmdZx2AYGnl4V3Py404HwZDlyeHVMr04CIQDRbq9D +aUQFFchUa3FTZfz8ebX7fHWf2FWn0lZnDdDFczAKBggqhkjOPQQDAwNnADBkAjA1 +ldlaOhPIkaNo2XF/9Xao2cf22Si04HDoQQTyo/4DhiqKl+Q+8w/n5z4RJ0qE9/wC +MBewzs9sTWl5F6Y6ZjfvsAk7CtZa+bRofih97NDk4MMyJcqvRkeaFBE1+vZJOHv7 +hQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEVjCCAj6gAwIBAgIQY5WTY8JOcIJxWRi/w9ftVjANBgkqhkiG9w0BAQsFADBP +MQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFy +Y2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMTAeFw0yNDAzMTMwMDAwMDBa +Fw0yNzAzMTIyMzU5NTlaMDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBF +bmNyeXB0MQswCQYDVQQDEwJFODB2MBAGByqGSM49AgEGBSuBBAAiA2IABNFl8l7c +S7QMApzSsvru6WyrOq44ofTUOTIzxULUzDMMNMchIJBwXOhiLxxxs0LXeb5GDcHb +R6EToMffgSZjO9SNHfY9gjMy9vQr5/WWOrQTZxh7az6NSNnq3u2ubT6HTKOB+DCB +9TAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMB +MBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFI8NE6L2Ln7RUGwzGDhdWY4j +cpHKMB8GA1UdIwQYMBaAFHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEB +BCYwJDAiBggrBgEFBQcwAoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzATBgNVHSAE +DDAKMAgGBmeBDAECATAnBgNVHR8EIDAeMBygGqAYhhZodHRwOi8veDEuYy5sZW5j +ci5vcmcvMA0GCSqGSIb3DQEBCwUAA4ICAQBnE0hGINKsCYWi0Xx1ygxD5qihEjZ0 +RI3tTZz1wuATH3ZwYPIp97kWEayanD1j0cDhIYzy4CkDo2jB8D5t0a6zZWzlr98d +AQFNh8uKJkIHdLShy+nUyeZxc5bNeMp1Lu0gSzE4McqfmNMvIpeiwWSYO9w82Ob8 +otvXcO2JUYi3svHIWRm3+707DUbL51XMcY2iZdlCq4Wa9nbuk3WTU4gr6LY8MzVA +aDQG2+4U3eJ6qUF10bBnR1uuVyDYs9RhrwucRVnfuDj29CMLTsplM5f5wSV5hUpm +Uwp/vV7M4w4aGunt74koX71n4EdagCsL/Yk5+mAQU0+tue0JOfAV/R6t1k+Xk9s2 +HMQFeoxppfzAVC04FdG9M+AC2JWxmFSt6BCuh3CEey3fE52Qrj9YM75rtvIjsm/1 +Hl+u//Wqxnu1ZQ4jpa+VpuZiGOlWrqSP9eogdOhCGisnyewWJwRQOqK16wiGyZeR +xs/Bekw65vwSIaVkBruPiTfMOo0Zh4gVa8/qJgMbJbyrwwG97z/PRgmLKCDl8z3d +tA0Z7qq7fta0Gl24uyuB05dqI5J1LvAzKuWdIjT1tP8qCoxSE/xpix8hX2dt3h+/ +jujUgFPFZ0EVZ0xSyBNRF3MboGZnYXFUxpNjTWPKpagDHJQmqrAcDmWJnMsFY3jS +u1igv3OefnWjSQ== +-----END CERTIFICATE----- diff --git a/traefik/certs/ugh.key b/traefik/certs/ugh.key new file mode 100644 index 0000000..39ecc89 --- /dev/null +++ b/traefik/certs/ugh.key @@ -0,0 +1,6 @@ +-----BEGIN PRIVATE KEY----- +MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDDvBmnWB/siZiSWTfe0 +Ex6WCyVmxrzP8KXGHK+a4uR2RgFM7DUv/uv/hMrowKMApIehZANiAASMfeFM3W3V +u7sGL6OF/LBPkSCa3Yd7GsDBcv4s1fqaD6J9fBvxoo0KeYfGmqsC7BgsWF8X32gw +HcdKuDwRVS++BS+Ak8lunlNmx0AqQuu937nKP8HdgHVh6H9jMTOG/xo= +-----END PRIVATE KEY----- diff --git a/traefik/certs/ugh.pem b/traefik/certs/ugh.pem new file mode 100644 index 0000000..18bb74f --- /dev/null +++ b/traefik/certs/ugh.pem @@ -0,0 +1,48 @@ +-----BEGIN CERTIFICATE----- +MIIDqzCCAzGgAwIBAgISBpW9i29bmbCOTNRag5uGuP+nMAoGCCqGSM49BAMDMDIx +CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQDEwJF +NzAeFw0yNjAxMTYxOTQ1NTJaFw0yNjA0MTYxOTQ1NTFaMBMxETAPBgNVBAMMCCou +dWdoLmltMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEjH3hTN1t1bu7Bi+jhfywT5Eg +mt2HexrAwXL+LNX6mg+ifXwb8aKNCnmHxpqrAuwYLFhfF99oMB3HSrg8EVUvvgUv +gJPJbp5TZsdAKkLrvd+5yj/B3YB1Yeh/YzEzhv8ao4ICJzCCAiMwDgYDVR0PAQH/ +BAQDAgeAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8E +AjAAMB0GA1UdDgQWBBRDfAOFC0uLO5vRuG+P09jJGFO2RjAfBgNVHSMEGDAWgBSu +SJ7chx1EoG/aouVgdAR4wpwAgDAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAKG +Fmh0dHA6Ly9lNy5pLmxlbmNyLm9yZy8wGwYDVR0RBBQwEoIIKi51Z2guaW2CBnVn +aC5pbTATBgNVHSAEDDAKMAgGBmeBDAECATAtBgNVHR8EJjAkMCKgIKAehhxodHRw +Oi8vZTcuYy5sZW5jci5vcmcvNDAuY3JsMIIBDQYKKwYBBAHWeQIEAgSB/gSB+wD5 +AHcAZBHEbKQS7KeJHKICLgC8q08oB9QeNSer6v7VA8l9zfAAAAGbyI1QAgAABAMA +SDBGAiEA06qp8w9zvvPbZTvRaAdW9cmLLSAVdXObCFNlrgUhdbwCIQDemwN3Spyw +65f/weztNAIp2ZiRppqC1Aqyjq3IU54EbQB+AKXJeJJdV0YXgocN2IlmC1xVZIt9 +AEDy7AdoUdGIaRn3AAABm8iNU5YACAAABQAvMZZZBAMARzBFAiEAiVPBPoGNN9Z9 +OuXDCNkEen6k4Rwx9CwMceXD1Ki+t8sCIBO22g6U/vYwn+FSc8pq4FNOm0kklNtX +IUupbEirWb6cMAoGCCqGSM49BAMDA2gAMGUCMEeHTG1AWcUR4bjL7DS+oJwIfFxP +VJYSFsWeBXbSGTL/q3iNnO/2zkPwR6wiRKNlcgIxAJUKZAWAmHaMaqKKk1a0krdK +QQZSRC0xJYLDg7FRMXJg5nflZID0oZt/OQyW2nGLKA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEVzCCAj+gAwIBAgIRAKp18eYrjwoiCWbTi7/UuqEwDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjQwMzEzMDAwMDAw +WhcNMjcwMzEyMjM1OTU5WjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg +RW5jcnlwdDELMAkGA1UEAxMCRTcwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARB6AST +CFh/vjcwDMCgQer+VtqEkz7JANurZxLP+U9TCeioL6sp5Z8VRvRbYk4P1INBmbef +QHJFHCxcSjKmwtvGBWpl/9ra8HW0QDsUaJW2qOJqceJ0ZVFT3hbUHifBM/2jgfgw +gfUwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD +ATASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBSuSJ7chx1EoG/aouVgdAR4 +wpwAgDAfBgNVHSMEGDAWgBR5tFnme7bl5AFzgAiIyBpY9umbbjAyBggrBgEFBQcB +AQQmMCQwIgYIKwYBBQUHMAKGFmh0dHA6Ly94MS5pLmxlbmNyLm9yZy8wEwYDVR0g +BAwwCjAIBgZngQwBAgEwJwYDVR0fBCAwHjAcoBqgGIYWaHR0cDovL3gxLmMubGVu +Y3Iub3JnLzANBgkqhkiG9w0BAQsFAAOCAgEAjx66fDdLk5ywFn3CzA1w1qfylHUD +aEf0QZpXcJseddJGSfbUUOvbNR9N/QQ16K1lXl4VFyhmGXDT5Kdfcr0RvIIVrNxF +h4lqHtRRCP6RBRstqbZ2zURgqakn/Xip0iaQL0IdfHBZr396FgknniRYFckKORPG +yM3QKnd66gtMst8I5nkRQlAg/Jb+Gc3egIvuGKWboE1G89NTsN9LTDD3PLj0dUMr +OIuqVjLB8pEC6yk9enrlrqjXQgkLEYhXzq7dLafv5Vkig6Gl0nuuqjqfp0Q1bi1o +yVNAlXe6aUXw92CcghC9bNsKEO1+M52YY5+ofIXlS/SEQbvVYYBLZ5yeiglV6t3S +M6H+vTG0aP9YHzLn/KVOHzGQfXDP7qM5tkf+7diZe7o2fw6O7IvN6fsQXEQQj8TJ +UXJxv2/uJhcuy/tSDgXwHM8Uk34WNbRT7zGTGkQRX0gsbjAea/jYAoWv0ZvQRwpq +Pe79D/i7Cep8qWnA+7AE/3B3S/3dEEYmc0lpe1366A/6GEgk3ktr9PEoQrLChs6I +tu3wnNLB2euC8IKGLQFpGtOO/2/hiAKjyajaBP25w1jF0Wl8Bbqne3uZ2q1GyPFJ +YRmT7/OXpmOH/FVLtwS+8ng1cAmpCujPwteJZNcDG0sF2n/sc0+SQf49fdyUK0ty ++VUwFj9tmWxyR/M= +-----END CERTIFICATE----- diff --git a/traefik/compose.yml b/traefik/compose.yml new file mode 100644 index 0000000..e25c138 --- /dev/null +++ b/traefik/compose.yml @@ -0,0 +1,56 @@ +name: traefik +services: + traefik: + image: traefik:v3.6 + container_name: traefik + restart: unless-stopped + env_file: .env + security_opt: + - no-new-privileges:true + networks: + - traefik_proxy + - proxy_network + ports: + - target: 80 + published: 80 + protocol: tcp + mode: host + - target: 443 + published: 443 + protocol: tcp + mode: host + - 10.8.0.1:9850:8080 + dns: + - 1.1.1.1 + - 8.8.8.8 + volumes: + - /etc/localtime:/etc/localtime:ro + - ./certs:/certs:ro + - /var/run/docker.sock:/var/run/docker.sock:ro + - ./config/traefik.yml:/etc/traefik/traefik.yml:ro + - ./config/dynamic_conf:/etc/traefik/dynamic_conf:ro + - ./data/acme.json:/acme.json + environment: + - TRAEFIK_DASHBOARD_PASS=${TRAEFIK_DASHBOARD_PASS} + labels: + - traefik.enable=true + - traefik.http.routers.dashboard.rule=Host(`traefik.gravitywell.xyz`) + - traefik.http.routers.dashboard.service=api@internal + - traefik.http.routers.dashboard.entrypoints=websecure + - traefik.http.routers.dashboard.tls=true # replaces certresolver line + - traefik.http.routers.dashboard.middlewares=internal-allowlist + - traefik.http.middlewares.internal-allowlist.ipAllowList.sourcerange=127.0.0.1/32,10.8.0.0/24,192.168.0.0/16,172.16.0.0/12 # v3: ipAllowList not ipwhitelist + - traefik.docker.network=traefik_proxy + deploy: + resources: + limits: + cpus: "0.50" + memory: 512M + reservations: + cpus: "0.10" + memory: 128M +networks: + traefik_proxy: + external: true + proxy_network: + external: true diff --git a/traefik/config/dynamic_conf/certs.yml b/traefik/config/dynamic_conf/certs.yml new file mode 100644 index 0000000..49f211f --- /dev/null +++ b/traefik/config/dynamic_conf/certs.yml @@ -0,0 +1,7 @@ +# /opt/stacks/traefik/config/dynamic_conf/certs.yml +tls: + certificates: + - certFile: /certs/gravitywell.pem + keyFile: /certs/gravitywell.key + - certFile: /certs/ugh.pem + keyFile: /certs/ugh.key diff --git a/traefik/config/dynamic_conf/services.yaml b/traefik/config/dynamic_conf/services.yaml new file mode 100644 index 0000000..7cd080e --- /dev/null +++ b/traefik/config/dynamic_conf/services.yaml @@ -0,0 +1,534 @@ +http: + routers: + gravitywell-xyz-router: + rule: "Host(`gravitywell.xyz`)" + service: "gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + gw-ugh-im-router: + rule: "Host(`gw.ugh.im`) || Host(`jellyfin.gravitywell.xyz`) || Host(`jfin.gravitywell.xyz`)" + service: "gw-ugh-im-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + lw-gravitywell-xyz-router: + rule: "Host(`lw.gravitywell.xyz`) || Host(`lw.ugh.im`)" + service: "lw-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + rimgo-gravitywell-xyz-router: + rule: "Host(`rimgo.gravitywell.xyz`)" + service: "rimgo-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + radarr-gravitywell-xyz-router: + rule: "Host(`radarr.gravitywell.xyz`)" + service: "radarr-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + searx-gravitywell-xyz-router: + rule: "Host(`searx.gravitywell.xyz`)" + service: "searx-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + wiz-gravitywell-xyz-router: + rule: "Host(`wiz.gravitywell.xyz`)" + service: "wiz-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + sonarr-gravitywell-xyz-router: + rule: "Host(`sonarr.gravitywell.xyz`)" + service: "sonarr-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + seerr-gravitywell-xyz-router: + rule: "Host(`seerr.gravitywell.xyz`)" + service: "seerr-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + speedtest-gravitywell-xyz-router: + rule: "Host(`speedtest.gravitywell.xyz`)" + service: "speedtest-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } +# piped-gravitywell-xyz-router: +# rule: "Host(`piped.gravitywell.xyz`) || Host(`pipedapi.gravitywell.xyz`) || Host(`pipedproxy.gravitywell.xyz`)" +# service: "piped-gravitywell-xyz-service" +# entryPoints: ["websecure"] +# tls: { certResolver: "namecheap-resolver" } + feishin-gravitywell-xyz-router: + rule: "Host(`feishin.gravitywell.xyz`)" + service: "feishin-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + m-gravitywell-xyz-router: + rule: "Host(`m.gravitywell.xyz`) || Host(`m.pl.ugh.im`) || Host(`pl.ugh.im`)" + service: "m-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + navi-gravitywell-xyz-router: + rule: "Host(`navi.gravitywell.xyz`) || Host(`nv.ugh.im`)" + service: "navi-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + redlib-gravitywell-xyz-router: + rule: "Host(`redlib.gravitywell.xyz`)" + service: "redlib-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + ugh-im-router: + rule: "Host(`ugh.im`)" + service: "ugh-im-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + mx-ugh-im-router: + rule: "Host(`mx.ugh.im`)" + service: "mx-ugh-im-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + st-ugh-im-router: + rule: "Host(`st.ugh.im`)" + service: "st-ugh-im-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + fr-ugh-im-router: + rule: "Host(`fr.ugh.im`)" + service: "fr-ugh-im-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + hd-ugh-im-router: + rule: "Host(`hd.ugh.im`) || Host(`hedge.gravitywell.xyz`)" + service: "hd-ugh-im-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + pb-ugh-im-router: + rule: "Host(`pb.ugh.im`) || Host(`privbin.gravitywell.xyz`)" + service: "pb-ugh-im-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + rd-ugh-im-router: + rule: "Host(`rd.ugh.im`)" + service: "rd-ugh-im-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + qr-ugh-im-router: + rule: "Host(`qr.ugh.im`) || Host(`quetre.gravitywell.xyz`)" + service: "qr-ugh-im-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + romm-gravitywell-xyz-router: + rule: "Host(`romm.gravitywell.xyz`)" + service: "romm-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + ch-ugh-im-router: + rule: "Host(`ch.ugh.im`)" + service: "ch-ugh-im-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + remote-override-ugh-im-router: + rule: "Host(`remote-override.ugh.im`)" + service: "remote-override-ugh-im-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + sw-ugh-im-router: + rule: "Host(`sw.ugh.im`)" + service: "sw-ugh-im-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + tasks-gravitywell-xyz-router: + rule: "Host(`tasks.gravitywell.xyz`)" + service: "tasks-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + peertube-gravitywell-xyz-router: + rule: "Host(`peertube.gravitywell.xyz`)" + service: "peertube-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + llm-gravitywell-xyz-router: + rule: "Host(`llm.gravitywell.xyz`)" + service: "llm-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + cloud-gravitywell-xyz-router: + rule: "Host(`cloud.gravitywell.xyz`) || Host(`nc.ugh.im`)" + service: "cloud-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + discourse-gravitywell-xyz-router: + rule: "Host(`discourse.gravitywell.xyz`) || Host(`forum.gravitywell.xyz`)" + service: "discourse-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + dumb-gravitywell-xyz-router: + rule: "Host(`dumb.gravitywell.xyz`)" + service: "dumb-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + proxitok-gravitywell-xyz-router: + rule: "Host(`proxitok.gravitywell.xyz`) || Host(`pt.ugh.im`)" + service: "proxitok-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + slsk-gravitywell-xyz-router: + rule: "Host(`slsk.gravitywell.xyz`)" + service: "slsk-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + pie-gravitywell-xyz-router: + rule: "Host(`pie.gravitywell.xyz`)" + service: "pie-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + gs-ugh-im-router: + rule: "Host(`gs.ugh.im`)" + service: "gs-ugh-im-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + jf-ugh-im-router: + rule: "Host(`jf.ugh.im`)" + service: "jf-ugh-im-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + grafana-gravitywell-xyz-router: + rule: "Host(`grafana.gravitywell.xyz`) || Host(`stats.gravitywell.xyz`)" + service: "grafana-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + jstat-gravitywell-xyz-router: + rule: "Host(`jstat.gravitywell.xyz`)" + service: "jstat-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + talk-gravitywell-xyz-router: + rule: "Host(`talk.gravitywell.xyz`)" + service: "talk-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + bs-ugh-im-router: + rule: "Host(`bs.ugh.im`) || Host(`stash.gravitywell.xyz`)" + service: "bs-ugh-im-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + jit-ugh-im-router: + rule: "Host(`jit.ugh.im`) || Host(`jitsi.gravitywell.xyz`) || Host(`meet.gravitywell.xyz`)" + service: "jit-ugh-im-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + mc-ugh-im-router: + rule: "Host(`mc.ugh.im`)" + service: "mc-ugh-im-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + kuma-gravitywell-xyz-router: + rule: "Host(`kuma.gravitywell.xyz`) || Host(`ut.ugh.im`)" + service: "kuma-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + floatilla-gravitywell-xyz-router: + rule: "Host(`floatilla.gravitywell.xyz`) || Host(`flt.ugh.im`)" + service: "floatilla-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + nostr-gravitywell-xyz-router: + rule: "Host(`nostr.gravitywell.xyz`)" + service: "nostr-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + nostrudel-gravitywell-xyz-router: + rule: "Host(`nostrudel.gravitywell.xyz`) || Host(`nsdl.ugh.im`)" + service: "nostrudel-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + primal-gravitywell-xyz-router: + rule: "Host(`primal.gravitywell.xyz`) || Host(`prml.ugh.im`)" + service: "primal-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + stoat-gravitywell-xyz-router: + rule: "Host(`stoat.gravitywell.xyz`)" + service: "stoat-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + rocketchat-gravitywell-xyz-router: + rule: "Host(`rocketchat.gravitywell.xyz`)" + service: "rocketchat-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + bbs-ugh-im-router: + rule: "Host(`bbs.ugh.im`) || Host(`enigma.gravitywell.xyz`)" + service: "bbs-ugh-im-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + spacebar-gravitywell-xyz-router: + rule: "Host(`spacebar.gravitywell.xyz`)" + service: "spacebar-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + searx-ugh-im-router: + rule: "Host(`searx.ugh.im`)" + service: "searx-ugh-im-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + fluxer-gravitywell-xyz-router: + rule: "Host(`fluxer.gravitywell.xyz`)" + service: "fluxer-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + test-gravitywell-xyz-router: + rule: "Host(`test.gravitywell.xyz`)" + service: "test-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + akkoma-gravitywell-xyz-router: + rule: "Host(`akkoma.gravitywell.xyz`)" + service: "akkoma-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + poke-gravitywell-xyz-router: + rule: "Host(`poke.gravitywell.xyz`)" + service: "poke-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + movim-gravitywell-xyz-router: + rule: "Host(`movim.gravitywell.xyz`)" + service: "movim-gravitywell-xyz-service" + entryPoints: ["websecure"] + tls: { certResolver: "namecheap-resolver" } + services: + gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:9797" + gw-ugh-im-service: + loadBalancer: + servers: + - url: "http://10.8.0.10:8096" + lw-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:3515" + rimgo-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.10:3492" + radarr-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.10:7878" + searx-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.10:8282" + wiz-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.10:5690" + sonarr-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.10:8989" + seerr-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.10:5055" + speedtest-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.10:3300" +# piped-gravitywell-xyz-service: +# loadBalancer: +# servers: +# - url: "http://10.8.0.1:8107" + feishin-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.10:9180" + m-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:29500" + navi-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.10:24533" + redlib-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.10:29501" + ugh-im-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:9798" + mx-ugh-im-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:6167" + st-ugh-im-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:13300" + fr-ugh-im-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:8281" + hd-ugh-im-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:3969" + pb-ugh-im-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:8956" + rd-ugh-im-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:29503" + qr-ugh-im-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:3629" + romm-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.10:17920" + ch-ugh-im-service: + loadBalancer: + servers: + - url: "http://10.8.0.2:2283" + remote-override-ugh-im-service: + loadBalancer: + servers: + - url: "http://aw2cd67.glddns.com:56599" + sw-ugh-im-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:3666" + tasks-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:3456" + peertube-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.10:29511" + llm-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.2:3235" + cloud-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.50:26145" + discourse-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.50:20080" + dumb-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:1485" + proxitok-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:14861" + slsk-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.10:5030" + pie-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.10:8030" + gs-ugh-im-service: + loadBalancer: + servers: + - url: "http://10.8.0.99:8096" + jf-ugh-im-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:8096" + grafana-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:3010" + jstat-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.10:3963" + talk-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:19683" + bs-ugh-im-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:5059" + jit-ugh-im-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:8297" + mc-ugh-im-service: + loadBalancer: + servers: + - url: "http://10.8.0.2:8922" + kuma-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:3259" + floatilla-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:3267" + nostr-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:3601" + nostrudel-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:8756" + primal-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:8757" + stoat-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.20:947" + rocketchat-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.50:3127" + bbs-ugh-im-service: + loadBalancer: + servers: + - url: "http://10.8.0.50:8915" + spacebar-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.20:8657" + searx-ugh-im-service: + loadBalancer: + servers: + - url: "http://10.8.0.1:8282" + fluxer-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.20:9802" + test-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.50:9797" + akkoma-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.50:29500" + poke-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.50:6003" + movim-gravitywell-xyz-service: + loadBalancer: + servers: + - url: "http://10.8.0.20:1692" diff --git a/traefik/config/traefik.yml b/traefik/config/traefik.yml new file mode 100644 index 0000000..ad4811b --- /dev/null +++ b/traefik/config/traefik.yml @@ -0,0 +1,30 @@ +api: + dashboard: true + insecure: true +log: + level: DEBUG +certificatesResolvers: + namecheap-resolver: + acme: + email: admin@gravitywell.xyz + storage: /acme.json + dnsChallenge: + provider: namecheap + delayBeforeCheck: 120 +entryPoints: + web: + address: :80 + http: + redirections: + entryPoint: + to: websecure + scheme: https + websecure: + address: :443 +providers: + docker: + endpoint: unix:///var/run/docker.sock + exposedByDefault: false + file: + directory: /etc/traefik/dynamic_conf + watch: true diff --git a/traefik/data/acme.json b/traefik/data/acme.json new file mode 100644 index 0000000..6445e65 --- /dev/null +++ b/traefik/data/acme.json @@ -0,0 +1,33 @@ +{ + "namecheap-resolver": { + "Account": { + "Email": "admin@gravitywell.xyz", + "Registration": { + "body": { + "status": "valid" + }, + "uri": "https://acme-v02.api.letsencrypt.org/acme/acct/3156142051" + }, + "PrivateKey": "MIIJKQIBAAKCAgEA03F4+kLW+NQNhZJEI4NXUb3qSfyJjGEFxFOlkLa2Z9qY7zZmAoTGS/8hX2gpdPfpEJTfI5dgFZ/USk3DrvYYVnY08XvULkCgNUSO9fzJ2S3tLXWIaYr8ftIUBkrnJ2ZPLiyDjQjyH5XIXRBM3V///p5nceXHo5vZcZ9sGL0VI6ENKLLEgvTe4DB48yVyOXjEMPAZGB7Rohku7blMR3arM6SgBog0LhdVw2MF1XP9afPjpIm/8Uxm5u3/GsK7t37qnONE5qyXfgq/OqcyvJXCW9LGBaZ800FUm7Mk9gn94T36L/6IhT7Ref8ffBJh5L3Bei+XLThzqSK2D6rkzVrmekZCE7ZwE4VRBCKKbqUc0Cz/cqVZsDTt5H0bvczINW3HGqMEUtfAsRDHA41Z1hCU795X2eJHRSd+dcLLbWPIft/WfomuOtHcMWnVTpOtp5hGRVTPFwMvdeMXJMAD6FX6qa/SsNvnaBKWlH3oyhkqZ1CyehbqyPmh2ha+IWoNsWX7lfTClSzZRI5G5Sa0fCuK3IPgKbZN+NjE6zDvDTqSG0iqG3aRZmiFbjC0UHjxl5c3bKSB8srzuaAa2CuAApBgHAzs8nSegAqsqAf2grEFvmTamid6c6zV8o+zDU7Sh+jkM3gJxKbdsto9/B6m9aKvWO6D6kfVd3IAZtOsbYvqtd8CAwEAAQKCAgAQK5lo6juug+kU0f7MCHthEPkd92Y9ih36ybrbul1wy9LuWGaswqK3pSdUOI8TFvKIBhqaijUa8kI1/IR+mOt7kUazQRkVAHRAHqIgRdjZ9x0wYNCx4aM1v7MwWAIdjUF48oaM/qYlrDrKgzidpX3aZxraJwyBgqW6fsqxiaRYOTTca++DZF63Hn3henel1YqLg5EnuxOlJe/k1krzHCwzot9qIHh9HeO9MZF8pYY32CMMrkwzk/g6qPDdhw78FYSzwt2+FmzvgrrlLWw/5+QZSaFDRVw+e7yQu76T4me8FhVQHlMqfYdfoRczUeSSrcBiK8mP98VAphruT893tP/zLkIev41H1BNKuii6iEZGcyoSNcxRkT7kSyn9tOvj3DDQHH0BGBRtYDre8DiThiHm/DivWKtojHCDlrWMCFBroUQTBhsOhxqgrVohV0QvirPsRUg4t2fMyaw8z74Yxo4/eldanApXPf0vBz3Qp3m7h1GSk+wYES6jxxcxKffmt8jKqrRlOo/Om8uHWMaC9faTZe/RJ7wkRRyDJN/CP8LWIWhzYX2xk6CeR09O1flwJXR7DsWFgKU1Fi0y1KJugl9+XhGxxucO59x1TwSLDTfBOxSuyIA39LbApeBMVLs6RPveEyZq4zPJtLqOKXkL6bJjXNrJu6ldrOEP6HqE0knOwQKCAQEA1wxnrN/2nOO+pINhdnKeNu1lS32ZmYBnSpSVqv1PPkgii79Ojd7lboaLEPaLuT4VoKMtryBXiBfCtEMLbPeIon0Zet7fZGamYeF0Mt2BFKb+GNrMu1mk7BpYbveHa9dSU6GBrW0RNQzOJnNUsc8ZDfFND2vW4MA2zcNqgtbu+84PFa/Q298MxIaJpKKDUq24cANAl9ZsbTCaNzGgoZ4JLs8hD8drj5XUFyj56Nne61d0/u5sUUWCBibuGn76UFF+0durJ0vq4iCgUDG0yfaIKLPjsFtRCoASNZoc2Og7D+jVnGhR0FTFQD7DJ5Zhwy7QyvLZB2bHUErl5Cc0B8Z1RwKCAQEA+7VQa9WcH6KoTdaYRBN604P8mrN2jYLc6eGfGIRfVkfKQlJrnSmjWenixfbQo3lS4SuaWw5ZTTbjuN52GIEUZC7iMDXjYy9FkRrxZNJBIZS04w3uXD1kMmOkrnk/yHoRqRJ9Qj9UmePSyGYkBcdvtr8JMuCbM02rKi5kTYTFSojur7ircZ0yfxG3bpDcoM3z1Zasqo6ioEBU/a2IaHoAUEYzTgM79GfXzhKvk41LoGbJGjUex5aiFANj8ha7l87U7W05yYANJLKVvWUU6ZJ1OMjW492HT6fwddXQIIlN27uri7hudvxREu9X0H2bs3U9msYORCftt/Dq5MW4WetmqQKCAQEAhTIZxOmzRdmJ6zu00jiL5lmDtA5HZNwzHe6KBS6ANoNXYldLwHOeh6at3APY5xOdMbHgSeguTwzoe95K5WMsLfhuH7yLgRRTWaza2+Z2XORR3fMne6M6k0J+I70NE656P3J5b4Fudv1HcmlcvAUZ75jVsgeJQAvN5gRzpDacLzqh/Ty4kHbG4bKy7lX6IOuYoUhiaalV3wuLeUQzyeaoqWWBhNRvuq+CfhXTNHY9rGavAHeMf4odztGuCJs9TyIq+rCkgeJzyTuMEB+5ap5YF13UWRc2StqobKrX00GD04bTR90VT4Qx6Gj3Vz29r7b/e7SO2BbAvOqnGXlusKIrYQKCAQA6Q3QEIgPrhrkym1PPnjq2Lz0Pii8M/peoQ6OSB0ISNLfqti1WycaYD32AmWseC/1VRcSLAz1ElEoOBuCLN4XC0t9kjXS/BrgxqGzsC4csAMIGNLlR/Jvu1gXOpR5Qh4EDA9aeuQ4aORQXcx0vgUSopnu4nSkPrRDLyMVK9Eq+wAeQAU0eFWcU5sLxAvMu/b1NWX1KVY3rTjjeJ4cFuAfOjRFfI3yDTG41szmVDAXPcTtnp5giVwnZXBeMeBqgPy4mbzwLGmrwba4fkwBOOKqNpF+piyPBGnycqgttHJs7G6vPwbdAL5OMsH5BMnISDjdeVi4DNMLf6xJUNjhACC9RAoIBAQDPVG+TeEYyJKP9MvxnZ+R0vmlisuIa3uLq7Jr7VNI4tseYitEmn9SjKryd17P1NriAUSE1P25a0oVHlN4l8f+1/j1bwbhemPm0rLIhsVmTe9YBHjPvqMmNoScxoy2QtW00h2PQ6CQPhulD6A3wU2DQdFz2Wf+DAeWd5WPyEwZDpZ2eNtfhDJbaIvNQSofW/93TQwKdIWoAJUPFyLWKjHjlNjrOAwbJzmvLp9Y4RhsHHArfSoyzHqIZENhq7Emi8qCBLTkkTFnE4Kuljt5NkwfL+RwVWChF+uaWRjaoPMxDI4t0MEDYBCy0hBpaMuEgi55HM8p+k11XrTDgYnsLtrkx", + "KeyType": "4096" + }, + "Certificates": [ + { + "domain": { + "main": "m.pl.ugh.im" + }, + "certificate": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUdDekNDQlBPZ0F3SUJBZ0lTQlRpMFJ5UXBRQitoUlBEeFNORHVUQ0pOTUEwR0NTcUdTSWIzRFFFQkN3VUEKTURNeEN6QUpCZ05WQkFZVEFsVlRNUll3RkFZRFZRUUtFdzFNWlhRbmN5QkZibU55ZVhCME1Rd3dDZ1lEVlFRRApFd05TTVRJd0hoY05Nall3TXpFNE1Ea3dPREEyV2hjTk1qWXdOakUyTURrd09EQTFXakFjTVJvd0dBWURWUVFECkV4RnRMbWR5WVhacGRIbDNaV3hzTG5oNWVqQ0NBaUl3RFFZSktvWklodmNOQVFFQkJRQURnZ0lQQURDQ0Fnb0MKZ2dJQkFNejFSTHJCUEd2QVhuQ1dZWmFBOUV1ZG0vMW1aVzJJWDBEUjV1ZXU3dm02ZllHTkpSUFRTdmlOZlRKQgpMRm1RdU1aNXpnVGZUMXl0Y0dJaVQySXpzQjBzbzk2bktzVk45T1pYK0ppN0dHY2hXQ1pCOWxYNCtZZXViY0hSCmNGMVBjQ1l4b1pLQlg2bktkcFcxeXpSbUErT3E1L21kOFppdTRVNVE4R0g5MDFDeEpjK0dQNm9MNVROdXVFMjYKdk5ubkQ2eTRUZy9YdjJkZXhRbFRuQytheGJwRjhlWlI5QnRra1E1MEE3QVBsTVJpaWNyZUliTjlXcklTWkpiSgorMGxUL0dPaHJlM0RTREVOUk9yUnlqVHhJck9KVHZzS0JQTlZEdURyNGUxN1gzNGpORWVaa1NBNUk4QitLVXNoCjFCUTlodnhDbitmR1pSRXFjYWZ4M0REc1N1djd6bXBtQUxhOUpRL0F2SnJwMWpDQ0l3NWY1ZGFlQ0ZhYTNzaDcKWW1JSzJpQVM2Qnd0NDhHcHZNQ1JTS2hEVS9kaXJkZm1LK3l3b0lGZjhzd2tSTTRnTGgxa2JlT3JkblMzazk2TApKZWp0NWQwclBmRHEwOWo3RlRDYXphU2RvZ3N0c05abUFZNElSZkNZNnJDOEhpai9UeVRraWtkSnU3UFdya0o1CjR3dFQ0bnVIMTRZMyszN0ZYZVhEVjJrYTJzVEN6Y3V4NEtWRFZZcVpDWEpucWM1THAvM3dzRlRaYURtdnhycnUKcm1kR3hhL3luRmpVcUN1QWJPaWkvWSszS2NveG81THhoWjVNWWJxN081QnRSRXdFUWdtOUh1dTFwNUNEOGpLVQp2S200NmhRdDBPZk5PV1BEUDdsek1WcUZkb3ljaFQrMkg2by9IZGcyR1VVUSs5VnBBZ01CQUFHamdnSXVNSUlDCktqQU9CZ05WSFE4QkFmOEVCQU1DQmFBd0V3WURWUjBsQkF3d0NnWUlLd1lCQlFVSEF3RXdEQVlEVlIwVEFRSC8KQkFJd0FEQWRCZ05WSFE0RUZnUVVXQXNqUDhPVUdMUWRTRkpQVFJLKzc4UFpxM3N3SHdZRFZSMGpCQmd3Rm9BVQpBTFVwOGkyT2J6SG9tMHl0ZUQ3NjNPa00wZEl3TXdZSUt3WUJCUVVIQVFFRUp6QWxNQ01HQ0NzR0FRVUZCekFDCmhoZG9kSFJ3T2k4dmNqRXlMbWt1YkdWdVkzSXViM0puTHpBMEJnTlZIUkVFTFRBcmdoRnRMbWR5WVhacGRIbDMKWld4c0xuaDVlb0lMYlM1d2JDNTFaMmd1YVcyQ0NYQnNMblZuYUM1cGJUQVRCZ05WSFNBRUREQUtNQWdHQm1lQgpEQUVDQVRBdUJnTlZIUjhFSnpBbE1DT2dJYUFmaGgxb2RIUndPaTh2Y2pFeUxtTXViR1Z1WTNJdWIzSm5MemM0CkxtTnliRENDQVFNR0Npc0dBUVFCMW5rQ0JBSUVnZlFFZ2ZFQTd3QjFBRW1jbTJuZUhYenMvRGJlellka3ByaGIKcndxSGdCblJWVkw3NmVzcDNmakRBQUFCblFCcFZaRUFBQVFEQUVZd1JBSWdSdzFmeHJ3U3JBbnlHMm56dDkxTgpvWWI2YU9say9qV3VFWTg4RzYwWktqTUNJRUdMWXZ0ditzZnR3bGdOUlhTREREWUc5OEF2aW9mV0xjSTNuNUlCCkNVQ0lBSFlBRm9NdHEvQ3BKUThQOERxbFJmL0l2OGdqMElkTDlnUXBKL2puSHpNVDlmb0FBQUdkQUdsVnBRQUEKQkFNQVJ6QkZBaUFQNFVub0xFQWFhRG10aWlvdmxOUHBVa3JBWnIya2ROOThmNXZDaDhaT3B3SWhBSmZTQ1I4cgp4RXRkTUN1azNINkI0UDFGcjVpTkxuYXpZanpHbzZqMlVrRkdNQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUJBUUJKCm5sbTlvMWw4YVNnenJIaTUwZDNtWTVOTXJJVFFyc1E0ZUl3MlJ2eE8zQmJSYWVrTzBYcHNRL3ZoZEJHdEtwMW8KeWRrNUZXNEJ1T01qT0NMYTR3dS8vRVpJMkJGNG45YTI2ZEtaRnRMTGxBRlNEdGdrSndDS1BpM0JTL0p6ZmNsLwpCWWFZU0laeEdqV2J0Q1haaE1ONk8wTGNydm1KMXRPYjhLVHV3NUVNR1g0V1ZPb1BHNW9vd1A2VVdJWmQ3YTB4CjNHaVlJTXk1dTdKeTZXeXJlZnJBYlY2QlVUUGFVU2RKbVF6Ky9VdERKV2dMTHRVRHFObGt2SW5XMko3Q0MzT0MKWC8vNTJLSFl3MnM3bi80VGIwdkFDa1pTNmFBMVQ3S3VrT3lrYjh2YnozWGVUOUNCZUF2cUQ3OWhDN1phdXdIMwpwRE5xTWJvU3NZRzU5ZUhMZ2Q5RwotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCgotLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJRkJqQ0NBdTZnQXdJQkFnSVJBTUlTTWt0d3FiU1JjZHhBOStLRkpqd3dEUVlKS29aSWh2Y05BUUVMQlFBdwpUekVMTUFrR0ExVUVCaE1DVlZNeEtUQW5CZ05WQkFvVElFbHVkR1Z5Ym1WMElGTmxZM1Z5YVhSNUlGSmxjMlZoCmNtTm9JRWR5YjNWd01SVXdFd1lEVlFRREV3eEpVMUpISUZKdmIzUWdXREV3SGhjTk1qUXdNekV6TURBd01EQXcKV2hjTk1qY3dNekV5TWpNMU9UVTVXakF6TVFzd0NRWURWUVFHRXdKVlV6RVdNQlFHQTFVRUNoTU5UR1YwSjNNZwpSVzVqY25sd2RERU1NQW9HQTFVRUF4TURVakV5TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCCkNnS0NBUUVBMnBnb2RLMitsUDQ3NEI3aTVVdDFxeXdTZisybkF6SitOcGZzNkRHUHBST05DNWt1SHMwQlVUMU0KNVNodUNWVXhxcVVpWFhMMExRZkNUVUE4M3dFanVYZzM5UnBsTWpUbWhuR2RCTytFQ0Z1OUFocVo2NllCQUpwegprRzJQb2dlZzBKZlQya1ZoZ1RVOUZQbkV3RjlxM0F1V0dyQ2Y0eXJxdlNyV21NZWJjYXM3ZEE4ODI3Smd2bHBMClRoanAyeXB6WElsaFpaNys3VHlteTA1djVKNzVBRWF6L3hsTkttT3pqbWJHR0lWd3gxQmxienQwNVVpRER3aFkKWFMwam5WNmovdWpiQUtIUzlPTVpUZkx1ZXZZbm51WE5uQzJpOG4rY0Y2M3ZFemM1MGJUSUxFSFdoc0RwN0NINApXUnQvdVRwOG4xd0JuV0lFd2lpOUNxMDh5aERzR3dJREFRQUJvNEg0TUlIMU1BNEdBMVVkRHdFQi93UUVBd0lCCmhqQWRCZ05WSFNVRUZqQVVCZ2dyQmdFRkJRY0RBZ1lJS3dZQkJRVUhBd0V3RWdZRFZSMFRBUUgvQkFnd0JnRUIKL3dJQkFEQWRCZ05WSFE0RUZnUVVBTFVwOGkyT2J6SG9tMHl0ZUQ3NjNPa00wZEl3SHdZRFZSMGpCQmd3Rm9BVQplYlJaNW51MjVlUUJjNEFJaU1nYVdQYnBtMjR3TWdZSUt3WUJCUVVIQVFFRUpqQWtNQ0lHQ0NzR0FRVUZCekFDCmhoWm9kSFJ3T2k4dmVERXVhUzVzWlc1amNpNXZjbWN2TUJNR0ExVWRJQVFNTUFvd0NBWUdaNEVNQVFJQk1DY0cKQTFVZEh3UWdNQjR3SEtBYW9CaUdGbWgwZEhBNkx5OTRNUzVqTG14bGJtTnlMbTl5Wnk4d0RRWUpLb1pJaHZjTgpBUUVMQlFBRGdnSUJBSTkxMEFuUGFuWklaVEtTM3JWRXlJVjI5QldFakFLL2R1dXo4ZUw1Ym9Tb1ZwSGhra3YzCjRlb0FlRWlQZFpMajVFWjdHMkFySUsrZ3poVGxSUTFxNEZLR3BQUGFGQlNwcVYveGJVYjVVbEFYUU9ua0huM20KRlZqK3FZdjg3L1dlWStCbTRzTjNPeDhCaHlhVTdVQVEzTGVaN04xWDAxeHhRZTR3SUFBRTNKVkxVQ2lIbVpMKwpxb0NVdGdZSUZQZ2NnMzUwUU1VSVdneFBYTkdFbmNUOTIxbmU3bmx1STAyVjhwTFVtQ2xxWE9zQ3dVTHcrUFZPClpDQjdxT014eE1Cb0NVZUwyTGw0b01wT1NyNXBKQ3BMTjN0UkEyczZQMUtMczlUU3JWaE9rKzdMWDI4Tk1VbEkKdXNRL254TEpJRDBSaEFlRnRQanlPQ09zY1FCQTUzK05SalNDYWs3UDRBNWpYN3BwbWtjSkVDTCtTMGkza1hWVQp5NU1lNUJiclU4OTczalpOdi9heDYrWks2VE04aldtaW1MNm9mNk9yWDdaVTZFMldxYXp6c0ZyTEczbzJreVNiCnpsaFNnSjgxQ2w0dHYzU2JZaVlYbkpFeEtRdnpmODNEWW90b3gzZjBmd3Y3eGxuMUEyWkxwbENiME8rbC9BSzAKWUUwRFMyRlB4U0FIaTBpd01mVzJuTkhKclhjWTNMTEhENzdnUmdqZTRFdmV1YmkyeHhhK05tay9obWhMZElFVAppVkRGYW5vQ3JNVklwUTU5WFdIa3pkRm1vSFhIQlY3b2liVmpHU083VUxTUTdNSjFOejUxcGh1REpTZ0FJVTdBCjB6ckxuT3JBai9kZnJsRVdSaEN2QWdidXdMWlgxQTJzak5qWG9QT0hic1BpeStsTzFLRjgvWFk3Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K", + "key": "LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlKSndJQkFBS0NBZ0VBelBWRXVzRThhOEJlY0paaGxvRDBTNTJiL1dabGJZaGZRTkhtNTY3dSticDlnWTBsCkU5TksrSTE5TWtFc1daQzR4bm5PQk45UFhLMXdZaUpQWWpPd0hTeWozcWNxeFUzMDVsZjRtTHNZWnlGWUprSDIKVmZqNWg2NXR3ZEZ3WFU5d0pqR2hrb0ZmcWNwMmxiWExOR1lENDZybitaM3htSzdoVGxEd1lmM1RVTEVsejRZLwpxZ3ZsTTI2NFRicTgyZWNQckxoT0Q5ZS9aMTdGQ1ZPY0w1ckZ1a1h4NWxIMEcyU1JEblFEc0ErVXhHS0p5dDRoCnMzMWFzaEprbHNuN1NWUDhZNkd0N2NOSU1RMUU2dEhLTlBFaXM0bE8rd29FODFVTzRPdmg3WHRmZmlNMFI1bVIKSURrandINHBTeUhVRkQyRy9FS2Y1OFpsRVNweHAvSGNNT3hLNi92T2FtWUF0cjBsRDhDOG11bldNSUlqRGwvbAoxcDRJVnByZXlIdGlZZ3JhSUJMb0hDM2p3YW04d0pGSXFFTlQ5Mkt0MStZcjdMQ2dnVi95ekNSRXppQXVIV1J0CjQ2dDJkTGVUM29zbDZPM2wzU3M5OE9yVDJQc1ZNSnJOcEoyaUN5MncxbVlCamdoRjhKanFzTHdlS1A5UEpPU0sKUjBtN3M5YXVRbm5qQzFQaWU0ZlhoamY3ZnNWZDVjTlhhUnJheE1MTnk3SGdwVU5WaXBrSmNtZXB6a3VuL2ZDdwpWTmxvT2EvR3V1NnVaMGJGci9LY1dOU29LNEJzNktMOWo3Y3B5akdqa3ZHRm5reGh1cnM3a0cxRVRBUkNDYjBlCjY3V25rSVB5TXBTOHFianFGQzNRNTgwNVk4TS91WE14V29WMmpKeUZQN1lmcWo4ZDJEWVpSUkQ3MVdrQ0F3RUEKQVFLQ0FnQW83eDlmOFRJQkR6V05aT3R1cEtpbDVYOS9GNUZRVS9rNk4vSFcrZUF1cmlsYzAzVEJSZVRtU1ZQawowcEZwL2ZaNVpXQlpKc1J4N1EzUis2cEJJYk9kMEFtV2NXcWdaMVp2SHNpK3NEZEtlYVZpVnJBOU1YR2N3S0NaCklody85cHFlZGpFZjBvanBuMDhaeldvZE4vYTA1TEJaOFVxTVJQa29yQSttY294ZXhGS1o1T1VZTURJQm1LNWsKajlRaDdQejdjUC9lT0NlNUhIdGJ4b0FlSGRvNXZyaDJXSTNaWHJkOTNIdlVFUGlVVkYzU3o1U0poWkswbCtuUgpGOXdCSkMzM05CWkpzMFBhMEJ5Z2pXL0dMUmJTSnExSWhCTERDb3pqTFJrOVZmT1hmSzUzVWx0aXhTYTN6anF2CkQ3Mk1vVkV4VnBrYk1FdUZKeVgxOWQ4VlFrd2dBOHZMOFBoOUExMzB3WlZOSVlHWHNqeWtGL2J6U2xLc3pjdE4KVzNLN0lPRUkwM3p4djlYOWdBS0MrQUh5SG9nRXMwaDA1VndyN2VrSXcrRWdOWFhvWExvNXhpcFFqV1pnM3dnTApTUDVBQVhCc0dkSEJyL0dOajRISkt2M29JWml5RHRVcGl5dzB6cWtDR2hsZjB4ZTZjK0ZGVzZQenBXZkFwcXZpCkM0MEw1M2x2NGxxdk80VVJ2TEwrZGJzaEtGZEV5c1FJd0FlVC9TaHJhUXlIaU5rWTRzR3Z0VGl5WGQzMVhoODcKQ2w3Q2JmVm1MYWlxWklxR0pUTGhremZDT2lsRFFvcktkalRiWUFtUXRjdEErTnMwY1hKMTBLUnhBUWNEWi9teQpxR2dlNzhLSEpwRTJSS1JnVjR3VXJCS3U4WisybE5YOHNMRUJmeHp5c2EycHRKMGtVUUtDQVFFQTE2OUN0a2lrCno3MWt2T3llRGhJU2lpWkY2RzFKc3FZYXRjcHduY2tZT1lTVWFjTG1rLy90S3VJemVUVmZVanh5b2tCeVltVU8KNVpPWmliRHVpUkNheVU3Z2FSNGZ0bEdDdFV0cENKK2xQeGJjUkI2OWhUc0ltYXJDMm1Xd2R3eUhneWxpVVpadwpEYTVJczg1SDN4ZkpaWUxqanhDL09iRElxci9oSHk0T25rSFE2eDhxVWZTZWExWU5mZ3lhOFYzcEc0QkhpSTFaCmU2OFNXbjBWSWF5aGljaGplUG5BSGxXTENTMzJ1YnM1aEgzY3lJVTlzRjhKUHpKWG1WQWVod05PelFEWGRvU3EKNm1ZVWlZUFlNZ2ZlWkJvUGtHR1dkRWp3OEhYMy9VRjYvR3RWWjVyOE9qbm01b3dFMmlNc1JVY0dwbW9UZG1HdgpWTFZWZUNrMHh1RlU5UUtDQVFFQTgwUzdXMS93cms5a3hTVnNxSGhEL2x0Y2J3cFZkMDRsSHFORjZuZHI1V1hjCjcyeFdzc0Q0YktBRFpJZmp3YnovYW9ZVFpJQnBUVHRjK1ZQZ2tWTWJOaDZvQkdlTjAxUkZlZWRuYlZVT01sbWYKZWtnNWNqOGIrUHlUVStBQU5WcWhkbnJadDk5NGNHcDJCTmhQQ1lKcitDY3RkdHJaT1J1RnlzWXNlcjNxbTVhMApSek1kbWR4SzdoTFFYOXhOY0dEdEQxRmI4clk5M0FXclBsV1c0cFN0OFlhdWlVN1A1MG5HRDRRU0NaekdDOUxTCjQ3UGRtMkRpUTk1ZlpZbHRLUjZJZGtHOSsrZ3RxenI3K0dtSG0yYTZLaHAvRW5lMlJvTmRlQXIwS092OUhuUSsKZlNJaFhOa0VSRGRqVDJRM3dBYXVhcjNLYkpOdjJtR1hQeGd3b2plV0pRS0NBUUJ6QUlBUnNhb3ZHazBjYnczWApjc3R2M2Zob2RkMVY1RHRac3hkWkNtQmdTdERYazVSZVZaZWZ4ZnlzSkVrdkVBd1BkMDJHS1Z4SURPdFEvNFl3Cmp5bjVMSlY3ZHhSeG9nU1BwaVhhODBTbzN3ZVRTdERDdVRkY3VEQXRRd3RVYnRuU2xiNVd3bC84NjNEWWJxVGoKejBzVFZUY0FrVzFrMVY0cHJTWGIrakxSTDBhMkYyZjVTdlV0UmpUcmdNMGM1WFhsdEFCd1R1M25oUEhFVGUxMgpoeFdhNGI0b1F3S3RLZTk0ZFltWWZydXNhVy9QZXp2cFRzTWZiemhHQnZKQUN3TjVTM21YT0NYcDFZUWR6cTczCi9qb1dKYzhtck9JTUh0aFpYbzFiL0E0WGlTT0FtcUxpYVAwMDhIT2wzQnMrMVNBMm0xakZSbEMyV2ZtNG1FQUwKeXhvQkFvSUJBRUJqRnJ2T251TmovQ1g2QzlKalVvdkdIcWI5TXpYS3B5Uit6b2lLWnpKbVRaM0pMUUZPOWZHNgpRR3VoVS9UNVV4a2N0NUZJTTViUGVZSThZeG5UeDBZQnd6SzNQZUNMVTRBNmNUT002WjhGL2FIZDcrWi9NYVlyCkk4dDFaRmk2empXUHVvUmlUM3hoa1M4akdYaEkzczdsZjdFUHA2TG4xL2Vka0RSRWhBMytTMlQwOEliQ3VjcGQKakcxeTM4UTR3MFhrb05PU3pMaXBmM09XTDhOMDJyMHNpcEdwSEhuNUdzVU1qY0doandHZUlWZEhTZ1pRRkZNbQpUbFdQbENibi8vSmM0QzRHZTkvd1VyU2pLZE5GMDB4Rml4Q1dRdFpTK3JCRkplNlcxMzN5QW9BWVFvQlNxRUJ0CjhJa1kyM0NsMUJCSWY0VlJXSytTV1BmSUxVY2lNMGtDZ2dFQU5FemZIbFdTTU9PditxMFNHN2FCZWlFNkk5bE0KbkkxYTJadktYWlZ2bHpPQlhZODNKUTRIYnliVmZFcER1THh4eHZUdGZacFZubTZLb0FnazRpZWFaTThOemx4QQpIVVhyZHNiNFBLb1Fxb0YzUlpFRFFKVDRWeTJ4ZTZDYUZwNWRpUER4a2hEVkFVMDk0Z1EzOEt4SFk1NTlvNXF1CitQSmlHeFgrNFhzOHJhWklIbDNLVk1TRk8yeUkralhwQlNlRUVmNmoybzZ4QjJ3NFZRa0c2dWVxMXY3Q2g5OXYKcld3THM4S241N2ZKRDgxYk0vNHZWcEhWZlBSWC96aEpFT2MxL1RQdjQveFVEeW9URU8xRWZRdWhVcVo4L3ZMUApHYytVdGg5TFhhUzQyV0NzVHUvdjlNbXV2MVdhN1hPQTRWYUg3WDZjQ3lPbG5LRGJMb0J1cVB3cGpnPT0KLS0tLS1FTkQgUlNBIFBSSVZBVEUgS0VZLS0tLS0K", + "Store": "default" + }, + { + "domain": { + "main": "proxy.piped.gravitywell.xyz" + }, + "certificate": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUdQVENDQlNXZ0F3SUJBZ0lTQnJWWW42bHNFV2pMWGM3WjQ5Z2pFa3I2TUEwR0NTcUdTSWIzRFFFQkN3VUEKTURNeEN6QUpCZ05WQkFZVEFsVlRNUll3RkFZRFZRUUtFdzFNWlhRbmN5QkZibU55ZVhCME1Rd3dDZ1lEVlFRRApFd05TTVRJd0hoY05Nall3TXpFNU1Ua3dPVEE0V2hjTk1qWXdOakUzTVRrd09UQTNXakFnTVI0d0hBWURWUVFECkV4VndhWEJsWkM1bmNtRjJhWFI1ZDJWc2JDNTRlWG93Z2dJaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQ0R3QXcKZ2dJS0FvSUNBUUNsemJrSExaUFlOTmx2MUs2Mk1hY2pCbFhXUm54K3RkZUtyRVd2UlFud0s1TlhoNVpCTXBNYwp0ZTNkZDNEMDdPRzA0OTFMdmVpWmJjVEgvd2tIU2FYU2RSa1FrbXNLOTlXK3pJR0JsaGhyVUZIcnhXaGZrVVN6CmtOY2dvZFhKaVJrYVZSWFBMcFV6cHNKUDhCZHVWbDlpVGJkaWN4T0pOUkI1T29QZmRwQmtHSDloWGVTYXB2SzUKc1ZoQzZCOHAzTVlBbjVzU2h3UFMvYzg1eDdUbXhpVVNDQllacDFOcUpXOThaTlp5OWVZcGJROG1wdkJvWHFBagpLWnpnWDVCZVkyUE5TRkczVDg2SUptNU5HOHBucGxEV2NOU2JUWDhPUHpnMHVBUGgzell4cWNZQjIxQSswcnpUCldyeEFXTTQ1YSt3cEJUS0paZXFwNHZlelpreWl1eUc5ZzlxMXd3Y0dnd1dLWXBOWHA4eldZa3FtbHEwMGpZODkKaUVqeXVVSGgvM0xZL0ZyRDk0b3J1VnZCU0swTkNtaEVTR3ZZeGRaU3N0elVSVmoyV2NWQjhyVTlteVFsdnVqNQpodFl4dWZMZnk5TFI0T0dqQWxpZTFXWlpxaG50R2I1TmxCVFNETy8yMFNwQ3R6Wk9BM212OWxwN2lpSjI1YkF1CmFPQjN5clU4T3ExQnA3L2E3eVB6NlVOTy9HdzNpb1RpV1pCbGNRNHhrWHJmMUh2S2FpcUFFZG91LzBhTVZhTWwKMjBXQWVvNUs4R1A5a2NDMi91azlaV245emEyWmZ3QXlnb2ZGSDNUT0ROdUpRM1daOC9XSWVJdXJQKzJhbmkrUApmZUNPMXRaVHRmTGxTYStLMDNmWjEvWGJEZnA4UkorcXQ2di9kOEtYbU80RnBoR2FOLy9rZFFJREFRQUJvNElDClhEQ0NBbGd3RGdZRFZSMFBBUUgvQkFRREFnV2dNQk1HQTFVZEpRUU1NQW9HQ0NzR0FRVUZCd01CTUF3R0ExVWQKRXdFQi93UUNNQUF3SFFZRFZSME9CQllFRk1FdlVteloyaVFMME1KVXVBOE5sV2kvMjNYd01COEdBMVVkSXdRWQpNQmFBRkFDMUtmSXRqbTh4Nkp0TXJYZysrdHpwRE5IU01ETUdDQ3NHQVFVRkJ3RUJCQ2N3SlRBakJnZ3JCZ0VGCkJRY3dBb1lYYUhSMGNEb3ZMM0l4TWk1cExteGxibU55TG05eVp5OHdWd1lEVlIwUkJGQXdUb0lWY0dsd1pXUXUKWjNKaGRtbDBlWGRsYkd3dWVIbDZnaGh3YVhCbFpHRndhUzVuY21GMmFYUjVkMlZzYkM1NGVYcUNHM0J5YjNoNQpMbkJwY0dWa0xtZHlZWFpwZEhsM1pXeHNMbmg1ZWpBVEJnTlZIU0FFRERBS01BZ0dCbWVCREFFQ0FUQXZCZ05WCkhSOEVLREFtTUNTZ0lxQWdoaDVvZEhSd09pOHZjakV5TG1NdWJHVnVZM0l1YjNKbkx6RXlNeTVqY213d2dnRU4KQmdvckJnRUVBZFo1QWdRQ0JJSCtCSUg3QVBrQWR3QVdneTJyOEtrbER3L3dPcVZGLzhpL3lDUFFoMHYyQkNrbgorT2NmTXhQMStnQUFBWjBIdGZiVkFBQUVBd0JJTUVZQ0lRQ0l1aVprNzNINTdLRUZiRGJ3MWhwMHBkMnlkNlJSCnd3ZnV6cUlMMUthVlhBSWhBTU0yYWNSc3Q5cGY5NFNyZzVmN1RlQ0RUTW5CWkNPMkpUVGZUNENsL01NeEFINEEKcGNsNGtsMVhSaGVDaHczWWlXWUxYRlZraTMwQVFQTHNCMmhSMFlocEdmY0FBQUdkQjdYNEZRQUlBQUFGQURYVwp1MDhFQXdCSE1FVUNJRXFVNFp5VWtxYkhtMWhkWVFiaWI4RzFpZzA1eEJWaTB4QjRCTjlVd1dYWUFpRUEweXJuClprc0ZCek5WN3ZpcjM1US9QanRoYW9Nb1FxckppVjVVTU15ZGwvMHdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUIKQUJFWGdkMkhKRU0xcXQzaUZYSFhhRDd2VmttUU95UEtSdkQ3K09HOUw2TlQ5ZVptNXZXVkJ6S0NlUlo5blFUWQorOWVrZ1ZuOGxEV2kzSXV1RzUzUjl4c1JOcGd2NjFpVFIxK2VZTFpHZlJuZWMvSTk0RGZ4WWZCU0FML1Z5cUVRCmVrMXRzQWFNNGdzbzFwSVpPRElVKzF4UGk1WU9zTDFSZStyeHJndkh2Sk5ya1Y4bGxUaGNOa1RFMVBsUjlLd2YKb3dtV2VYQ1F1c1IzcTBJa2FGUTVXRXZsVnEvajR1aHNQVGd6RzRReSt1TktaTjhnVzBLTTFWT1NZTENaYWRFdQplQmNzVUlQeVBjVkU3Slg2K1J0Qm5zRXNabXc2R2FjNlhCSlZLMEdpUXN1bVVNL3BGZ1VhUTU0Y1pOSW9pUUJqCncybHVlWHk2ZDh3NWwzMnYyajNmYStrPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCgotLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJRkJqQ0NBdTZnQXdJQkFnSVJBTUlTTWt0d3FiU1JjZHhBOStLRkpqd3dEUVlKS29aSWh2Y05BUUVMQlFBdwpUekVMTUFrR0ExVUVCaE1DVlZNeEtUQW5CZ05WQkFvVElFbHVkR1Z5Ym1WMElGTmxZM1Z5YVhSNUlGSmxjMlZoCmNtTm9JRWR5YjNWd01SVXdFd1lEVlFRREV3eEpVMUpISUZKdmIzUWdXREV3SGhjTk1qUXdNekV6TURBd01EQXcKV2hjTk1qY3dNekV5TWpNMU9UVTVXakF6TVFzd0NRWURWUVFHRXdKVlV6RVdNQlFHQTFVRUNoTU5UR1YwSjNNZwpSVzVqY25sd2RERU1NQW9HQTFVRUF4TURVakV5TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCCkNnS0NBUUVBMnBnb2RLMitsUDQ3NEI3aTVVdDFxeXdTZisybkF6SitOcGZzNkRHUHBST05DNWt1SHMwQlVUMU0KNVNodUNWVXhxcVVpWFhMMExRZkNUVUE4M3dFanVYZzM5UnBsTWpUbWhuR2RCTytFQ0Z1OUFocVo2NllCQUpwegprRzJQb2dlZzBKZlQya1ZoZ1RVOUZQbkV3RjlxM0F1V0dyQ2Y0eXJxdlNyV21NZWJjYXM3ZEE4ODI3Smd2bHBMClRoanAyeXB6WElsaFpaNys3VHlteTA1djVKNzVBRWF6L3hsTkttT3pqbWJHR0lWd3gxQmxienQwNVVpRER3aFkKWFMwam5WNmovdWpiQUtIUzlPTVpUZkx1ZXZZbm51WE5uQzJpOG4rY0Y2M3ZFemM1MGJUSUxFSFdoc0RwN0NINApXUnQvdVRwOG4xd0JuV0lFd2lpOUNxMDh5aERzR3dJREFRQUJvNEg0TUlIMU1BNEdBMVVkRHdFQi93UUVBd0lCCmhqQWRCZ05WSFNVRUZqQVVCZ2dyQmdFRkJRY0RBZ1lJS3dZQkJRVUhBd0V3RWdZRFZSMFRBUUgvQkFnd0JnRUIKL3dJQkFEQWRCZ05WSFE0RUZnUVVBTFVwOGkyT2J6SG9tMHl0ZUQ3NjNPa00wZEl3SHdZRFZSMGpCQmd3Rm9BVQplYlJaNW51MjVlUUJjNEFJaU1nYVdQYnBtMjR3TWdZSUt3WUJCUVVIQVFFRUpqQWtNQ0lHQ0NzR0FRVUZCekFDCmhoWm9kSFJ3T2k4dmVERXVhUzVzWlc1amNpNXZjbWN2TUJNR0ExVWRJQVFNTUFvd0NBWUdaNEVNQVFJQk1DY0cKQTFVZEh3UWdNQjR3SEtBYW9CaUdGbWgwZEhBNkx5OTRNUzVqTG14bGJtTnlMbTl5Wnk4d0RRWUpLb1pJaHZjTgpBUUVMQlFBRGdnSUJBSTkxMEFuUGFuWklaVEtTM3JWRXlJVjI5QldFakFLL2R1dXo4ZUw1Ym9Tb1ZwSGhra3YzCjRlb0FlRWlQZFpMajVFWjdHMkFySUsrZ3poVGxSUTFxNEZLR3BQUGFGQlNwcVYveGJVYjVVbEFYUU9ua0huM20KRlZqK3FZdjg3L1dlWStCbTRzTjNPeDhCaHlhVTdVQVEzTGVaN04xWDAxeHhRZTR3SUFBRTNKVkxVQ2lIbVpMKwpxb0NVdGdZSUZQZ2NnMzUwUU1VSVdneFBYTkdFbmNUOTIxbmU3bmx1STAyVjhwTFVtQ2xxWE9zQ3dVTHcrUFZPClpDQjdxT014eE1Cb0NVZUwyTGw0b01wT1NyNXBKQ3BMTjN0UkEyczZQMUtMczlUU3JWaE9rKzdMWDI4Tk1VbEkKdXNRL254TEpJRDBSaEFlRnRQanlPQ09zY1FCQTUzK05SalNDYWs3UDRBNWpYN3BwbWtjSkVDTCtTMGkza1hWVQp5NU1lNUJiclU4OTczalpOdi9heDYrWks2VE04aldtaW1MNm9mNk9yWDdaVTZFMldxYXp6c0ZyTEczbzJreVNiCnpsaFNnSjgxQ2w0dHYzU2JZaVlYbkpFeEtRdnpmODNEWW90b3gzZjBmd3Y3eGxuMUEyWkxwbENiME8rbC9BSzAKWUUwRFMyRlB4U0FIaTBpd01mVzJuTkhKclhjWTNMTEhENzdnUmdqZTRFdmV1YmkyeHhhK05tay9obWhMZElFVAppVkRGYW5vQ3JNVklwUTU5WFdIa3pkRm1vSFhIQlY3b2liVmpHU083VUxTUTdNSjFOejUxcGh1REpTZ0FJVTdBCjB6ckxuT3JBai9kZnJsRVdSaEN2QWdidXdMWlgxQTJzak5qWG9QT0hic1BpeStsTzFLRjgvWFk3Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K", + "key": "LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlKS1FJQkFBS0NBZ0VBcGMyNUJ5MlQyRFRaYjlTdXRqR25Jd1pWMWtaOGZyWFhpcXhGcjBVSjhDdVRWNGVXClFUS1RITFh0M1hkdzlPemh0T1BkUzczb21XM0V4LzhKQjBtbDBuVVpFSkpyQ3ZmVnZzeUJnWllZYTFCUjY4Vm8KWDVGRXM1RFhJS0hWeVlrWkdsVVZ6eTZWTTZiQ1QvQVhibFpmWWsyM1luTVRpVFVRZVRxRDMzYVFaQmgvWVYzawptcWJ5dWJGWVF1Z2ZLZHpHQUorYkVvY0QwdjNQT2NlMDVzWWxFZ2dXR2FkVGFpVnZmR1RXY3ZYbUtXMFBKcWJ3CmFGNmdJeW1jNEYrUVhtTmp6VWhSdDAvT2lDWnVUUnZLWjZaUTFuRFVtMDEvRGo4NE5MZ0Q0ZDgyTWFuR0FkdFEKUHRLODAxcThRRmpPT1d2c0tRVXlpV1hxcWVMM3MyWk1vcnNodllQYXRjTUhCb01GaW1LVFY2Zk0xbUpLcHBhdApOSTJQUFloSThybEI0Zjl5MlB4YXcvZUtLN2xid1VpdERRcG9SRWhyMk1YV1VyTGMxRVZZOWxuRlFmSzFQWnNrCkpiN28rWWJXTWJueTM4dlMwZURob3dKWW50Vm1XYW9aN1JtK1RaUVUwZ3p2OXRFcVFyYzJUZ041ci9aYWU0b2kKZHVXd0xtamdkOHExUERxdFFhZS8ydThqOCtsRFR2eHNONHFFNGxtUVpYRU9NWkY2MzlSN3ltb3FnQkhhTHY5RwpqRldqSmR0RmdIcU9TdkJqL1pIQXR2N3BQV1ZwL2MydG1YOEFNb0tIeFI5MHpnemJpVU4xbWZQMWlIaUxxei90Cm1wNHZqMzNnanRiV1U3WHk1VW12aXROMzJkZjEydzM2ZkVTZnFyZXIvM2ZDbDVqdUJhWVJtamYvNUhVQ0F3RUEKQVFLQ0FnQkNyd2k1b0ZVVDRiMkp3cW81MEtKOTdiQmNLNkVxZlF3aFU4UDdCL05GU3VGSmxOaVRoRG15bEdFRQpiMk5Zdm1UUWtjeVJCK0lpd3drZnZxenM1MnZ2eHZTN3U0ZWRzNnVkdnpaZTNmVVlSQWVPb2FpbXR4QkFnQUpsCnQzRDZTMDl6VGNFbHdJQjFjNTQyOUVNWU4xakplcVJFemkrUFFXNU1zNElTUCtjMnVydVFkMmpYNGtsQThkaWoKb0NQWWZGaU9LNkw4d3B5QklWOVV4OE0wQllFblRXVkdFQXYyWnZQOXZiaWFKOWZYMVdzQWlxZXA4bFRKajVUdQprTURKbFlPd0xtUGZMQlBPb2xZK1lPejQzdVVvT2R6b1VUVEdrQnFVNldWMlZJWEJWNXl4Wm5sUnF3UVNwUzJOClc2b2xZZ2hyUHhIaVBNRXlibnhkQk1uUnNSMlNLeFJSNUxOTnIzSnpCd29vbmJOM2hmYlJmVE9PYkZQTnpia3cKMFErQW16VnVpMmFtSm9OanN2NEpEMm0xZU1tNFc1WDFzYmNqbXl5VXZJVTZuUUQzUkRPR2RPVXVVMDFManFoSwpQaGpUWVg1YVlnZFNMMTlPZlI5NmkxR054dC9tS2lTa3NnR0Y0V1lrTjJHWnc3YXI5QlhHZUNzK1pmSVBjTE5MCjRlcndqTm9MbVk0TWpwZkRXSlRVUnZMalM0UUpCNUErZFpkYTJHS2p3K0JBZzFONjBIb0FiMThMeEhCVkZXNlQKZ3Jta1dxekxjUXJ3TlNKeUZJYjZYQlMxTHpqTHlXYXZFdlZDd1c0emk1djFsNEc4Vm85a21uMk1xWDRJQW1TRQpyUWI2dmVTa0RPQlg0aEhrbS85ZUFaa29OQXlGNGI2dUdNaWdKemtIUmdLbjBQZGlpUUtDQVFFQXdubjJSRXNOClhFbVUzclQ5ZW1WdithVW9aNVAwWEVPa0d2YkRSK2NVbC9QVWVmL0VPZS9ocG9oSXdrU1dna0VjTEYvOVk5SmoKczVjY29DN1JtYkhHZmpYMTdLc013Nlk5Q2theHY2S0ZaT0FCYzRUMzQyazlJZnVobWhBYSs2THU0ZElRVkFDUgpkeUttemZEV3lKY2s1TTlMeVJrZTVJWWRPQkpjZXVibzNiSksyMXBhVkJERWhsMkozalVpM2daRHBBR0dKU3VsCnVvUW1sdDk5d0xEOVRncSt0Q2NHbmltdnNJOEdwcHhId2ltSVZKZU4yUGN1VlloWHVRN3hhVWoyTGFUNWNobXkKTnpzVDZueStyVFgxZlVQdXdyMFNHK2lDNi90SEorT295OXdrU2lYYTJkVnozVlBQUksybHJwUVZTSTE5aFBHYgo0VWw1RThBMmp3Z3hkd0tDQVFFQTJrR2pzQzJreUN3NjR0MHJzZkJWVWdoWjZ1aEQwMzJVQXhpcHdqS2lrTXNDCmp3SkZTaXBTanZrSnRpK0tKV2VueTdpMHlmTVpUU29FdGxZbU5IUlU5bzdwSGdpT3YrYnRGb1g1Rm9JazRqT2kKMVZpV1QySzFVaFJORlJHRmxGNVdNQlpJL1o2SUNSWVFtZE5WYXdQMUN3bjhqUHNQbmJSbHZWWXhCRlVjTGVPRApqZ0hmQ3dsZ1MzTTJucG9nSzExZzlpY2F3ZWwvQUoyWjJGbENzMzk1RFlvQllqbHNqQThZaFovV09DQ2tGOGdRClhnWWdKMkJyUXljYWRzTmJkRnFSd3BmRnNxTGQ2N2tVWVcwOUVQS3pxN01DSmN1MUJVQ2t6RnY1ajZOdm1oVjkKNk5PTmZmVms1RzQ5YlVYN3NmMlVQeDFyM2g4eXNPNENVSnE0UWthMGN3S0NBUUVBZ1p2QXVhRC9SWHN3Z1FCRQpVbmNhR2xtc3hPTUJIeUJoVlNzUjJIQ3o4OVVuelNyYy92UFZBaVNmd1FEdkFkNGN4YUl2Z0lCdHUvbkF0U3llCnVmeVYyZlZpY1psSngzYWFCYWc1dkFxM05oUm9RekhoOXloaStxdjE5blEzVjI4dUgwZmRZKzZCQTlJUE12OEkKVmVVTlRJU3U4RllTbGFDZ0JvZU9KTWFSZVhiaWxxL3Z0VWo3Z01VRUpoaHBwV2l0V2JjK1RMVjdIUVFIcDlOSQp2c3YxOVRZS0JJeGh4N1RtaHhlN0NmenJnZ1lsK3FLS2dZZXkxSVFxV29ZUDgrZ1JVVGc2bW9WdmxZbUU2Mmk1CnR6eFg0R1VPMGJBcVNuazZEOFdHbFpvUEc5WWFSV1JYSjRndlVOa1RNS1U5MzB5SHByUE5iSFdOT3FhNXo2VHgKZDMreFh3S0NBUUVBdDhaVFhSSmgwTWNsWWtjVzlzSkdKVWV3NXRKaDRoKzRWSThjeWM4M0FUSmZXaWx3VEkycwpiSVNYdjlieHZLTTJMNXk4WmR1VEwxMDFFSThqcGtGYUZTMnFic2FINUdBK3ZCdGM3SzN5L3FDNStHaWFVQWZ1ClkwbUN5ajJ4dTRkZmpTZ0dsNzg0RG1hTTNlbUw0QXM1OXV5V3dlTFllRk1nNDdkQ21NSk5jdnBDbUgxTTRJOHAKalA1YlBGck13WmJrQVFCV1VIY2FvRnNUNG83dVVoUUF5dnlzUTVmVXBXNUVtS2RJaW9RNWgyakhGMVNUR0hUZwpmRy9kb2FqSFJnYkkreEF1d0ViUkZCNElZaXpJSVpBcTUyVllacGpMT0x3QXg2NmVTV3MxbW9tRU5scURwazdOCmdHYXV4R2NNRXdoUkhuL1lodlRBQ3lpdHZFODYzVnVKcndLQ0FRQmVWcVoxejBaYzdJbkNSM3VmZnRYSExQeisKYWNjcjBoQjdpeXpVMjBWbVRteGZORG1JakJmUVUwNHo5cmN5R0k1WFJBcDk5S0VTaVBFOGtnMjRlMm1JWUY5TQpBK3BLZjk3c25td2hZYW53MUF6WlJhbytUaVlsTkJKRXNYd2dBWE9jNEUyeXVkemUvM0tWUjc4T0JuQVlzSXJoCjJscmUwMHFpbTVkRzJQNG9tUkFhZHBvVzEyRVF5QkVRRVdzdXdEbUdkZFI3UFVHeUdqUFE3R0dOeFhQMWM1cDkKQTlkVDBUN2JSdzdsOUxXa2MydTY4WlY1UXF5RG9MT3NtVGU1bjlKb1J0Slk1b1BzcHJrWDM2YmlTTmMrTlgvdwpmTGppT0d4ZnJWVXQzaTlVckQ5dXlXS0pOWWdZTENKaUJ4OCtWRzhjUmVwTzlnTm5aS0t5a1dHZTJYazUKLS0tLS1FTkQgUlNBIFBSSVZBVEUgS0VZLS0tLS0K", + "Store": "default" + } + ] + } +} \ No newline at end of file diff --git a/traefik/useless b/traefik/useless new file mode 100644 index 0000000..0e155d1 --- /dev/null +++ b/traefik/useless @@ -0,0 +1,31 @@ +version: '3.9' +services: + traefik: + image: traefik:v3.1 + container_name: traefik + restart: unless-stopped + security_opt: + - no-new-privileges:true + networks: + - traefik_proxy + ports: + - 80:80 + - 443:443 + - 9882:8080 + volumes: + - /etc/localtime:/etc/localtime:ro + - /var/run/docker.sock:/var/run/docker.sock:ro + - ./config/traefik.yml:/etc/traefik/traefik.yml:ro + - ./config/dynamic_conf:/etc/traefik/dynamic_conf:ro + - ./data/acme.json:/acme.json + environment: + - TRAEFIL_DASHBOARD_PASS=${TRAEFIK_DASHBOARD_PASS} + labels: + - traefik.enable=true + - traefik.http.routers.dashboard.rule=Host(`traefik.scumwanker.club`) + - traefik.http.routers.dashboard.service=api@internal + - traefik.http.routers.dashboard.entrypoints=websecure + - traefik.docker.network=traefik_proxy +networks: + traefik_proxy: + external: true