Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 606b3fe89f | |||
| c7340d011a | |||
| 9220ff54aa |
@@ -1,3 +1,7 @@
|
||||
<p align="center">
|
||||
<img src="favicon.svg" width="120" height="120" alt="GHOSTWIRE logo: the Hannya mask">
|
||||
</p>
|
||||
|
||||
# GHOSTWIRE
|
||||
|
||||
**ゴーストワイヤー** · A self-hosted WireGuard server manager in a single Go
|
||||
@@ -8,6 +12,8 @@ remove), hands out client configs as a download or QR code, and records traffic
|
||||
and connection history per peer. There are no install scripts and no
|
||||
dependencies on the server: the binary installs, updates and removes itself.
|
||||
|
||||

|
||||
|
||||
## Features
|
||||
|
||||
- **One file of state:** everything lives in `config.json`. The kernel is
|
||||
@@ -34,6 +40,19 @@ dependencies on the server: the binary installs, updates and removes itself.
|
||||
- **HTTPS built in:** Let's Encrypt, a self-signed certificate, your own
|
||||
certificate files, or plain HTTP behind a reverse proxy.
|
||||
|
||||
## Screenshots
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
|  |  |
|
||||
| **Peers:** status, endpoint, latency and traffic at a glance | **Peer:** traffic, latency, connection history and settings |
|
||||
|  |  |
|
||||
| **Server:** health, address plan, client defaults and firewall | **Settings:** users, web interface and API tokens |
|
||||
|  |  |
|
||||
| **My account:** profile, password and your app tokens | **Sign-in** |
|
||||
|
||||
The screenshots show sample data from the built-in simulator.
|
||||
|
||||
## Security
|
||||
|
||||
- **Client private keys are never stored.** A config is shown once, as a
|
||||
|
||||
@@ -66,6 +66,9 @@ a.brand, a.brand:hover { color: #fff; text-decoration: none; }
|
||||
.side .avatar { width: 28px; height: 28px; border-radius: 50%; background: #3a3b41; display: grid; place-items: center; flex: none; font-size: 13px; font-weight: 600; color: #fff; }
|
||||
.side .footrow { display: flex; justify-content: space-between; padding: 10px 12px 0; }
|
||||
.main { flex: 999 1 560px; min-width: 0; padding: 32px 32px 56px; }
|
||||
/* Beside the page (not stacked above it on a phone), the sidebar stays in
|
||||
place while the page scrolls, so the account link is always visible. */
|
||||
@media (min-width: 800px) { .side { position: sticky; top: 0; height: 100vh; height: 100dvh; overflow-y: auto; } }
|
||||
.wrap { max-width: 1120px; margin: 0 auto; display: flex; flex-direction: column; gap: 20px; }
|
||||
@media (max-width: 640px) { .main { padding: 20px 16px 40px; } }
|
||||
|
||||
|
||||
@@ -518,7 +518,7 @@
|
||||
h('span', null, h('strong', null, me.name), h('span', null, 'My account')))),
|
||||
h('div', { class: 'footrow' },
|
||||
h('button', { type: 'button', onClick: logout }, 'Sign out'),
|
||||
h('span', null, 'v' + me.version))));
|
||||
h('span', null, 'v' + me.version.replace(/^v/, '')))));
|
||||
main = h('main', { class: 'main', id: 'main' });
|
||||
app.replaceChildren(h('div', { class: 'shell' }, nav, main));
|
||||
refreshSide();
|
||||
|
||||
|
After Width: | Height: | Size: 64 KiB |
|
After Width: | Height: | Size: 97 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 195 KiB |
|
After Width: | Height: | Size: 96 KiB |
|
After Width: | Height: | Size: 147 KiB |
|
After Width: | Height: | Size: 81 KiB |