diff --git a/.gitignore b/.gitignore index 2e85c98..4ce5750 100644 --- a/.gitignore +++ b/.gitignore @@ -130,4 +130,5 @@ dmypy.json staticfiles/ userfiles/ -testdata.py \ No newline at end of file +testdata.py +*.sqlite3 diff --git a/deploy/dev/Dockerfile.backend b/deploy/dev/Dockerfile.backend new file mode 100644 index 0000000..4eb1ded --- /dev/null +++ b/deploy/dev/Dockerfile.backend @@ -0,0 +1,16 @@ +# Use an official Python runtime as instance_a parent image +FROM python:3.9 + +# Set environment variables +ENV PYTHONDONTWRITEBYTECODE 1 +ENV PYTHONUNBUFFERED 1 + +# Set work directory +WORKDIR /code + +# Install dependencies +COPY requirements.txt /code/ +RUN pip install --no-cache-dir -r requirements.txt + +# Run the application +CMD ["python", "manage.py", "runserver", "0.0.0.0:8000", "--insecure"] diff --git a/deploy/dev/Dockerfile.dns b/deploy/dev/Dockerfile.dns new file mode 100644 index 0000000..055bdc0 --- /dev/null +++ b/deploy/dev/Dockerfile.dns @@ -0,0 +1,16 @@ +# Use an official Python runtime as instance_a parent image +FROM python:3.9 + +# Set environment variables +ENV PYTHONDONTWRITEBYTECODE 1 +ENV PYTHONUNBUFFERED 1 + +# Set work directory +WORKDIR /dns + +COPY dns_server.py /dns/ + +RUN pip install dnslib + +# Run the application +CMD ["python", "dns_server.py"] diff --git a/deploy/dev/Dockerfile.frontend b/deploy/dev/Dockerfile.frontend new file mode 100644 index 0000000..85138e6 --- /dev/null +++ b/deploy/dev/Dockerfile.frontend @@ -0,0 +1,13 @@ +# Use an official Node.js runtime as instance_a parent image +FROM node:14 + +# Set work directory +WORKDIR /app + +# Install app dependencies +# A wildcard is used to ensure both package.json AND package-lock.json are copied +COPY package.json ./ + +RUN npm install + +CMD [ "npm", "run", "dev", "--", "--host"] diff --git a/deploy/dev/Dockerfile.proxy b/deploy/dev/Dockerfile.proxy new file mode 100644 index 0000000..095c80f --- /dev/null +++ b/deploy/dev/Dockerfile.proxy @@ -0,0 +1,14 @@ +FROM nginx:bookworm + +# snakeoil for localhost + +RUN apt-get update && \ + apt-get install -y openssl && \ + openssl genrsa -des3 -passout pass:x -out server.pass.key 2048 && \ + openssl rsa -passin pass:x -in server.pass.key -out server.key && \ + rm server.pass.key && \ + openssl req -new -key server.key -out server.csr \ + -subj "/C=US/ST=Denial/L=Springfield/O=Dis/CN=localhost" && \ + openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt &&\ + mv server.crt /etc/nginx/nginx.crt && \ + mv server.key /etc/nginx/nginx.key \ diff --git a/deploy/dev/Dockerfile.wiki b/deploy/dev/Dockerfile.wiki new file mode 100644 index 0000000..affa564 --- /dev/null +++ b/deploy/dev/Dockerfile.wiki @@ -0,0 +1,15 @@ +# Use an official Python runtime as instance_a parent image +FROM python:3.9 + +# Set environment variables +ENV PYTHONDONTWRITEBYTECODE 1 +ENV PYTHONUNBUFFERED 1 + +# Set work directory +WORKDIR /wiki + +# Install dependencies +RUN pip install --no-cache-dir mkdocs + +# Run the application +CMD ["mkdocs", "serve", "--dev-addr=0.0.0.0:8001"] diff --git a/deploy/dev/dns_server.py b/deploy/dev/dns_server.py new file mode 100644 index 0000000..1457699 --- /dev/null +++ b/deploy/dev/dns_server.py @@ -0,0 +1,72 @@ +import http.server +import socketserver +import urllib.parse +import dnslib +import base64 + +try: + + def resolve(zone, qname, qtype): + for record in zone: + if record["name"] == qname and record["type"] == qtype and "value" in record: + return record["value"] + + + class DnsHttpRequestHandler(http.server.BaseHTTPRequestHandler): + def do_GET(self): + try: + with open("/dns/zone.json", "r") as f: + import json + zone = json.load(f) + + url = urllib.parse.urlparse(self.path) + if url.path != "/dns-query": + self.send_response(404) + return + query = urllib.parse.parse_qs(url.query) + if "dns" not in query: + self.send_response(400) + return + query_base64 = query["dns"][0] + padded = query_base64 + "=" * (4 - len(query_base64) % 4) + raw = base64.b64decode(padded) + dns = dnslib.DNSRecord.parse(raw) + + response = dnslib.DNSRecord(dnslib.DNSHeader(id=dns.header.id, qr=1, aa=1, ra=1), q=dns.q) + + record = resolve(zone, dns.q.qname, dnslib.QTYPE[dns.q.qtype]) + if record: + if dns.q.qtype == dnslib.QTYPE.SRV: + print("SRV record") + reply = dnslib.SRV(record["priority"], record["weight"], record["port"], record["target"]) + response.add_answer(dnslib.RR(dns.q.qname, dns.q.qtype, rdata=reply)) + else: + response.header.rcode = dnslib.RCODE.NXDOMAIN + + print(response) + + self.send_response(200) + self.send_header("Content-type", "application/dns-message") + self.end_headers() + pack = response.pack() + self.wfile.write(pack) + return + except Exception as e: + print(f"Error: {e}") + self.send_response(500) + self.send_header("Content-type", "text/html") + self.end_headers() + self.wfile.write(b"Internal Server Error") + + + handler_object = DnsHttpRequestHandler + + PORT = 8053 + my_server = socketserver.TCPServer(("", PORT), handler_object) + + # Start the server + print(f"Starting server on port {PORT}") + my_server.serve_forever() + +except Exception as e: + print(f"Error: {e}") diff --git a/deploy/dev/instance_a/a.env b/deploy/dev/instance_a/a.env new file mode 100644 index 0000000..33c5b7e --- /dev/null +++ b/deploy/dev/instance_a/a.env @@ -0,0 +1,8 @@ + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG=True + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY='e*lm&*!j0_stqaiod$1zob(vs@aq6+n-i$1%!rek)_v9n^ue$3' + +ALLOWED_HOSTS="*" diff --git a/deploy/dev/instance_a/dns.json b/deploy/dev/instance_a/dns.json new file mode 100644 index 0000000..ead645f --- /dev/null +++ b/deploy/dev/instance_a/dns.json @@ -0,0 +1,3 @@ +[ + "127.0.0.3:5353" +] diff --git a/deploy/dev/instance_a/domains.json b/deploy/dev/instance_a/domains.json new file mode 100644 index 0000000..ad8f349 --- /dev/null +++ b/deploy/dev/instance_a/domains.json @@ -0,0 +1,3 @@ +[ + "a.localhost" +] diff --git a/deploy/dev/instance_a/nginx-a.dev.conf b/deploy/dev/instance_a/nginx-a.dev.conf new file mode 100644 index 0000000..b77f550 --- /dev/null +++ b/deploy/dev/instance_a/nginx-a.dev.conf @@ -0,0 +1,96 @@ +events {} + +http { + upstream backend { + server backend-a:8000; + } + + upstream frontend { + server frontend:5173; + } + + upstream wiki { + server wiki:8001; + } + + upstream dns { + server dns:8053; + } + + server { + + listen 8080 ssl; + server_name localhost; + + ssl_certificate /etc/nginx/nginx.crt; + ssl_certificate_key /etc/nginx/nginx.key; + + location /api { + proxy_set_header Host $host:$server_port; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Host $host:$server_port; + proxy_set_header X-Forwarded-Port $server_port; + proxy_pass http://backend; + } + + location /auth { + proxy_set_header Host $host:$server_port; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Host $host:$server_port; + proxy_set_header X-Forwarded-Port $server_port; + proxy_pass http://backend; + } + + location /docs { + proxy_pass http://backend/docs; + } + + location /static { + proxy_pass http://backend/static; + } + + location /wiki { + proxy_pass http://wiki/wiki; + } + + location /livereload { + proxy_pass http://wiki/livereload; + } + + location /local/ { + alias /var/www/; + try_files $uri.json =404; + add_header Content-Type application/json; + } + + location / { + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "Upgrade"; + proxy_set_header Host $host; + proxy_pass http://frontend; + } + + } + + # DoH server + server { + listen 5353 ssl; + server_name localhost; + + ssl_certificate /etc/nginx/nginx.crt; + ssl_certificate_key /etc/nginx/nginx.key; + + location /dns-query { + proxy_pass http://dns; + # allow any origin + add_header 'Access-Control-Allow-Origin' '*'; + add_header 'Access-Control-Allow-Methods' 'GET, OPTIONS'; + + } + } +} diff --git a/deploy/dev/instance_b/b.env b/deploy/dev/instance_b/b.env new file mode 100644 index 0000000..c0118ca --- /dev/null +++ b/deploy/dev/instance_b/b.env @@ -0,0 +1,7 @@ +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG=True + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY='7ccxjje%q@@0*z+r&-$fy3(rj9n)%$!sk-k++-&rb=_u(wpjbe' + +ALLOWED_HOSTS="*" diff --git a/deploy/dev/instance_b/nginx-b.dev.conf b/deploy/dev/instance_b/nginx-b.dev.conf new file mode 100644 index 0000000..bb6596c --- /dev/null +++ b/deploy/dev/instance_b/nginx-b.dev.conf @@ -0,0 +1,46 @@ +events {} + +http { + upstream backend { + server backend-b:8000; + } + + server { + + listen 8080 ssl; + server_name localhost; + + ssl_certificate /etc/nginx/nginx.crt; + ssl_certificate_key /etc/nginx/nginx.key; + + location /api { + #proxy_set_header X-Forwarded-For "$http_x_forwarded_for, $realip_remote_addr"; + proxy_set_header Host $host:$server_port; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Host $host:$server_port; + proxy_set_header X-Forwarded-Port $server_port; + proxy_pass http://backend; + } + + location /auth { + #proxy_set_header X-Forwarded-For "$http_x_forwarded_for, $realip_remote_addr"; + proxy_set_header Host $host:$server_port; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Host $host:$server_port; + proxy_set_header X-Forwarded-Port $server_port; + proxy_pass http://backend; + } + + location /docs { + proxy_pass http://backend/docs; + } + + location /static { + proxy_pass http://backend/static; + } + } +} diff --git a/deploy/dev/zone.json b/deploy/dev/zone.json new file mode 100644 index 0000000..5c8be9a --- /dev/null +++ b/deploy/dev/zone.json @@ -0,0 +1,24 @@ +[ + { + "name": "_toolshed-server._tcp.a.localhost.", + "type": "SRV", + "ttl": 60, + "value": { + "priority": 0, + "weight": 5, + "port": 8080, + "target": "127.0.0.1." + } + }, + { + "name": "_toolshed-server._tcp.b.localhost.", + "type": "SRV", + "ttl": 60, + "value": { + "priority": 0, + "weight": 5, + "port": 8080, + "target": "127.0.0.2." + } + } +] diff --git a/deploy/docker-compose.override.yml b/deploy/docker-compose.override.yml new file mode 100644 index 0000000..30b4de9 --- /dev/null +++ b/deploy/docker-compose.override.yml @@ -0,0 +1,78 @@ +version: '3.8' + +services: + backend-a: + build: + context: ../backend/ + dockerfile: ../deploy/dev/Dockerfile.backend + volumes: + - ../backend:/code + - ../deploy/dev/instance_a/a.env:/code/.env + - ../deploy/dev/instance_a/a.sqlite3:/code/db.sqlite3 + expose: + - 8000 + command: bash -c "python configure.py; python configure.py testdata; python manage.py runserver 0.0.0.0:8000 --insecure" + + backend-b: + build: + context: ../backend/ + dockerfile: ../deploy/dev/Dockerfile.backend + volumes: + - ../backend:/code + - ../deploy/dev/instance_b/b.env:/code/.env + - ../deploy/dev/instance_b/b.sqlite3:/code/db.sqlite3 + expose: + - 8000 + command: bash -c "python configure.py; python configure.py testdata; python manage.py runserver 0.0.0.0:8000 --insecure" + + frontend: + build: + context: ../frontend/ + dockerfile: ../deploy/dev/Dockerfile.frontend + volumes: + - ../frontend:/app:ro + - /app/node_modules + expose: + - 5173 + command: npm run dev -- --host + + wiki: + build: + context: ../ + dockerfile: deploy/dev/Dockerfile.wiki + volumes: + - ../mkdocs.yml:/wiki/mkdocs.yml + - ../docs:/wiki/docs + expose: + - 8001 + command: mkdocs serve --dev-addr=0.0.0.0:8001 + + proxy-a: + build: + context: ./ + dockerfile: dev/Dockerfile.proxy + volumes: + - ./dev/instance_a/nginx-a.dev.conf:/etc/nginx/nginx.conf:ro + - ./dev/instance_a/dns.json:/var/www/dns.json:ro + - ./dev/instance_a/domains.json:/var/www/domains.json:ro + ports: + - "127.0.0.1:8080:8080" + - "127.0.0.3:5353:5353" + + proxy-b: + build: + context: ./ + dockerfile: dev/Dockerfile.proxy + volumes: + - ./dev/instance_b/nginx-b.dev.conf:/etc/nginx/nginx.conf:ro + ports: + - "127.0.0.2:8080:8080" + + dns: + build: + context: ./dev/ + dockerfile: Dockerfile.dns + volumes: + - ./dev/zone.json:/dns/zone.json + expose: + - 8053 diff --git a/frontend/node_modules/.forgit b/frontend/node_modules/.forgit new file mode 100644 index 0000000..e69de29 diff --git a/mkdocs.yml b/mkdocs.yml index dadf43a..64c248f 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -24,3 +24,4 @@ extra_javascript: - https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.js extra_css: - toolshed.css +site_url: https://localhost:8080/wiki/