Browse Source

Update

master
user 3 weeks ago
parent
commit
c3e1883d49
  1. 218
      VPS.md
  2. BIN
      frontend/public/logo.png
  3. 6
      frontend/src/App.vue
  4. 2
      frontend/src/components/Navbar.vue
  5. 2
      frontend/src/stores/theme.js
  6. 16
      frontend/src/views/Login.vue

218
VPS.md

@ -0,0 +1,218 @@
# Infrastruktura produkcyjna
## Architektura
```
Internet → VPS (publiczne IP, nginx + SSL)
↕ WireGuard tunnel (szyfrowany, domowe IP ukryte)
192.168.2.66 (nginx, port 80)
↓ LAN
192.168.2.33 (docker-compose, port 80)
```
- Domowe IP nigdy nie jest widoczne publicznie
- SSL terminuje na VPS
- `.66` inicjuje połączenie WireGuard do VPS — zero port-forwardingu na domowym routerze
---
## 1. WireGuard
### Instalacja (VPS i .66)
```bash
apt install wireguard
```
### VPS — generowanie kluczy
```bash
wg genkey | tee /etc/wireguard/vps_private.key | wg pubkey > /etc/wireguard/vps_public.key
```
### .66 — generowanie kluczy
```bash
wg genkey | tee /etc/wireguard/home_private.key | wg pubkey > /etc/wireguard/home_public.key
```
### `/etc/wireguard/wg0.conf` na VPS
```ini
[Interface]
Address = 10.10.0.1/24
ListenPort = 51820
PrivateKey = <vps_private.key>
[Peer]
# .66 home server
PublicKey = <home_public.key>
AllowedIPs = 10.10.0.2/32
```
### `/etc/wireguard/wg0.conf` na .66
```ini
[Interface]
Address = 10.10.0.2/24
PrivateKey = <home_private.key>
[Peer]
# VPS
PublicKey = <vps_public.key>
Endpoint = <VPS_PUBLIC_IP>:51820
AllowedIPs = 10.10.0.1/32
PersistentKeepalive = 25
```
> `PersistentKeepalive = 25` — utrzymuje tunel przez NAT domowego routera
### Uruchomienie (obie maszyny)
```bash
systemctl enable --now wg-quick@wg0
```
### Weryfikacja
```bash
wg show # status tunelu
ping 10.10.0.1 # z .66 do VPS
ping 10.10.0.2 # z VPS do .66
```
---
## 2. Nginx na VPS
### Certyfikat SSL
```bash
apt install certbot python3-certbot-nginx
certbot certonly --nginx -d q2dropzone.xyz
```
### `/etc/nginx/sites-available/q2dropzone.xyz`
```nginx
server {
listen 80;
server_name q2dropzone.xyz;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name q2dropzone.xyz;
ssl_certificate /etc/letsencrypt/live/q2dropzone.xyz/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/q2dropzone.xyz/privkey.pem;
client_max_body_size 6g;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_connect_timeout 60s;
location / {
proxy_pass http://10.10.0.2:80;
proxy_http_version 1.1;
proxy_set_header Host $host;
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 https;
proxy_buffering off;
proxy_request_buffering off;
}
}
```
```bash
ln -s /etc/nginx/sites-available/q2dropzone.xyz /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx
```
---
## 3. Nginx na .66
### `/etc/nginx/sites-available/q2dropzone.xyz`
```nginx
server {
listen 80;
server_name q2dropzone.xyz;
client_max_body_size 6g;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_connect_timeout 60s;
location / {
proxy_pass http://192.168.2.33:80;
proxy_http_version 1.1;
proxy_set_header Host $host;
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 https;
proxy_buffering off;
proxy_request_buffering off;
}
}
```
```bash
ln -s /etc/nginx/sites-available/q2dropzone.xyz /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx
```
---
## 4. Firewall
### VPS
```bash
ufw allow 51820/udp # WireGuard
ufw allow 80/tcp # HTTP (redirect do HTTPS)
ufw allow 443/tcp # HTTPS
ufw enable
```
### .66
```bash
# port 80 tylko z WireGuard IP VPS-a
ufw allow in on wg0 from 10.10.0.1 to any port 80
ufw deny 80
ufw enable
```
---
## 5. .33 — uruchomienie aplikacji
```bash
git clone <repo> q2dropzone && cd q2dropzone
cp .env.example .env
nano .env # uzupełnij DB_PASSWORD, JWT_SECRET, DISK_ROOT
docker-compose up -d --build
```
---
## DNS
Rekord A dla `q2dropzone.xyz` → publiczne IP VPS (nie domowe).
---
## Przepływ requestu
```
klient
→ VPS:443 (SSL terminate, proxy_pass przez WireGuard)
→ .66:80 (proxy_pass przez LAN)
→ .33:80 (nginx w docker → backend Go)
```
Każdy nginx ma `proxy_buffering off` i `proxy_request_buffering off` — duże pliki streamowane bez buforowania na dysk.

BIN
frontend/public/logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

6
frontend/src/App.vue

@ -1,5 +1,11 @@
<template> <template>
<div class="min-h-screen bg-gray-50 dark:bg-gray-900 transition-colors duration-200"> <div class="min-h-screen bg-gray-50 dark:bg-gray-900 transition-colors duration-200">
<header
class="w-full"
style="height: 80px; background: black url('/logo.png') no-repeat center center; background-size: 100% auto;"
>
<router-link to="/" class="block w-full h-full" aria-label="Q2Dropzone" />
</header>
<Navbar /> <Navbar />
<main> <main>
<router-view /> <router-view />

2
frontend/src/components/Navbar.vue

@ -3,7 +3,7 @@
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex items-center justify-between h-16"> <div class="flex items-center justify-between h-16">
<router-link to="/" class="text-xl font-bold text-indigo-600 dark:text-indigo-400"> <router-link to="/" class="text-xl font-bold text-indigo-600 dark:text-indigo-400">
Dropzone Q2Dropzone
</router-link> </router-link>
<div class="flex items-center gap-4"> <div class="flex items-center gap-4">

2
frontend/src/stores/theme.js

@ -2,7 +2,7 @@ import { defineStore } from 'pinia'
import { ref } from 'vue' import { ref } from 'vue'
export const useThemeStore = defineStore('theme', () => { export const useThemeStore = defineStore('theme', () => {
const dark = ref(localStorage.getItem('theme') === 'dark') const dark = ref(localStorage.getItem('theme') !== 'light')
function init() { function init() {
document.documentElement.classList.toggle('dark', dark.value) document.documentElement.classList.toggle('dark', dark.value)

16
frontend/src/views/Login.vue

@ -1,17 +1,17 @@
<template> <template>
<div class="min-h-[calc(100vh-4rem)] flex items-center justify-center bg-gray-50 py-12 px-4"> <div class="min-h-[calc(100vh-4rem)] flex items-center justify-center bg-gray-50 dark:bg-gray-900 py-12 px-4">
<div class="w-full max-w-md space-y-8"> <div class="w-full max-w-md space-y-8">
<div class="text-center"> <div class="text-center">
<h2 class="text-3xl font-bold text-gray-900">Sign in</h2> <h2 class="text-3xl font-bold text-gray-900 dark:text-white">Sign in</h2>
</div> </div>
<form @submit.prevent="handleLogin" class="bg-white shadow rounded-lg p-8 space-y-6"> <form @submit.prevent="handleLogin" class="bg-white dark:bg-gray-800 shadow rounded-lg p-8 space-y-6">
<div v-if="error" class="bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded-md text-sm"> <div v-if="error" class="bg-red-50 dark:bg-red-900/30 border border-red-200 dark:border-red-700 text-red-700 dark:text-red-400 px-4 py-3 rounded-md text-sm">
{{ error }} {{ error }}
</div> </div>
<div> <div>
<label for="username" class="block text-sm font-medium text-gray-700 mb-1"> <label for="username" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
Username Username
</label> </label>
<input <input
@ -20,12 +20,12 @@
type="text" type="text"
autocomplete="username" autocomplete="username"
required required
class="w-full border border-gray-300 rounded-md px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500" class="w-full border border-gray-300 dark:border-gray-600 rounded-md px-3 py-2 text-sm bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
/> />
</div> </div>
<div> <div>
<label for="password" class="block text-sm font-medium text-gray-700 mb-1"> <label for="password" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
Password Password
</label> </label>
<input <input
@ -34,7 +34,7 @@
type="password" type="password"
autocomplete="current-password" autocomplete="current-password"
required required
class="w-full border border-gray-300 rounded-md px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500" class="w-full border border-gray-300 dark:border-gray-600 rounded-md px-3 py-2 text-sm bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
/> />
</div> </div>

Loading…
Cancel
Save