Skip to content

Commit 30a237b

Browse files
authored
Merge pull request #19 from prajeeta15/p2p/dev-server
P2p/dev server #1
2 parents 6f0c76a + 42f981b commit 30a237b

File tree

5 files changed

+261
-88
lines changed

5 files changed

+261
-88
lines changed

HTTPS_SETUP.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# HTTPS dev server (LAN testing)
2+
This document explains how to create locally-trusted certificates and run the Vite dev server over HTTPS so you can test the app from other devices on the same LAN (phones, tablets, etc.).
3+
4+
## Recommended approach: use `mkcert` (easiest — certificates are trusted automatically)
5+
6+
### Install mkcert
7+
- macOS (Homebrew):
8+
```
9+
brew install mkcert
10+
brew install nss # for Firefox (optional)
11+
```
12+
- Windows (Chocolatey):
13+
```
14+
choco install mkcert
15+
```
16+
- Linux: download the mkcert binary from the project releases or use your package manager if available. Also install ```libnss3-tools``` for Firefox integration when required.
17+
18+
(See mkcert project for platform-specific install steps.)
19+
20+
### Generate certs (recommended)
21+
```npm run generate-cert```
22+
This script will prefer mkcert. If mkcert is installed it will create a locally-trusted certificate and install a local CA (if needed). The generated files will be placed in ```./certs/localhost.pem``` and ```./certs/localhost-key.pem```.
23+
24+
### Start the dev server
25+
```npm run dev:https```
26+
27+
### Open the site from another device on your LAN using your machine IP, for example:
28+
```https://192.168.1.23:5173```
29+
If the browser still warns about the certificate, confirm ```mkcert -install``` succeeded, or (if using the OpenSSL fallback) ```import certs/localhost.pem``` into the OS/browser trust store (instructions below).
30+
31+
## Fallback: OpenSSL (self-signed)
32+
33+
If you don't have mkcert installed, npm run generate-cert will try to create a self-signed cert with openssl. Self-signed certs will trigger browser warnings unless you import the cert into the trusted root store.
34+
Trusting the self-signed cert (example):
35+
- macOS (Keychain Access)
36+
1. Open Keychain Access.
37+
2. File → Import Items → select ```certs/localhost.pem```.
38+
3. Find the imported cert in login or System keychain, double-click it, expand "Trust" and set "When using this certificate" → "Always Trust".
39+
40+
- Windows
41+
1. Run certmgr.msc.
42+
2. Import ```certs/localhost.pem``` into ```Trusted Root Certification Authorities``` → Certificates.
43+
44+
- Linux
45+
1. Varies by distro/browser. On Debian/Ubuntu you can generally copy the PEM into ```/usr/local/share/ca-certificates/``` and run ```sudo update-ca-certificates```. Firefox may need manual import.
46+
47+
## HMR / websocket problems
48+
49+
If the dev server loads but HMR (hot module replacement) fails in other devices, set DEV_HMR_HOST to your host machine's LAN IP when starting the server. Example:
50+
51+
- macOS / Linux:
52+
```DEV_HMR_HOST=192.168.1.23 npm run dev:https```
53+
54+
- Windows (PowerShell):
55+
```
56+
$env:DEV_HMR_HOST = '192.168.1.23'
57+
npm run dev:https
58+
```
59+
This forces Vite to use that host in the HMR websocket URL.
60+
61+
## Troubleshooting
62+
63+
- If you see ```NET::ERR_CERT_AUTHORITY_INVALID```, your cert is not trusted. Prefer mkcert to avoid this.
64+
- If ```mkcert``` fails to install the local CA, try running ```mkcert -install``` manually (may request admin rights).
65+
- If ```openssl``` is not installed on Windows, use ```mkcert ``` instead, or install OpenSSL via MSYS2 / Git for Windows / other means.
66+
67+
## Security note
68+
Do not commit your private key to the repository. We add certs/ to .gitignore. If you prefer to share a single cert for your team, coordinate explicitly and treat the key as sensitive.

certs/.gitkeep

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# empty file to keep the certs directory in git

package.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,13 @@
1919
"vite": "5.4.9",
2020
"vite-plugin-pwa": "^0.17.4"
2121
},
22+
{
23+
"scripts": {
24+
"dev": "vite",
25+
"dev:https": "vite --host",
26+
"build": "vite build",
27+
"generate-cert": "node ./scripts/generate-cert.js"
28+
},
2229
"repository": {
2330
"type": "git",
2431
"url": "git+https://github.com/Rohit-554/Peer-Hacktoberfest.git"

scripts/generate-cert.js

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#!/usr/bin/env node
2+
3+
const { execSync } = require('child_process')
4+
const fs = require('fs')
5+
const path = require('path')
6+
const os = require('os')
7+
8+
9+
const repoRoot = path.resolve(__dirname, '..')
10+
const certDir = path.join(repoRoot, 'certs')
11+
if (!fs.existsSync(certDir)) fs.mkdirSync(certDir)
12+
13+
14+
const certFile = path.join(certDir, 'localhost.pem')
15+
const keyFile = path.join(certDir, 'localhost-key.pem')
16+
17+
18+
function getLocalIPs() {
19+
const nets = os.networkInterfaces()
20+
const results = []
21+
for (const name of Object.keys(nets)) {
22+
for (const net of nets[name]) {
23+
// we only care about IPv4 external addresses
24+
if (net.family === 'IPv4' && !net.internal) {
25+
results.push(net.address)
26+
}
27+
}
28+
}
29+
return results
30+
}
31+
32+
33+
const localIPs = getLocalIPs()
34+
const hosts = ['localhost', '127.0.0.1', '::1', ...localIPs]
35+
36+
37+
console.log('Generating cert for hosts:', hosts.join(', '))
38+
39+
40+
function run(cmd) {
41+
console.log('> ' + cmd)
42+
execSync(cmd, { stdio: 'inherit' })
43+
}
44+
45+
46+
// Try mkcert first (preferred — mkcert installs a local CA and will make certs trusted by browsers)
47+
try {
48+
execSync('mkcert -version', { stdio: 'ignore' })
49+
console.log('mkcert found — creating locally-trusted certs (mkcert will install a local CA if necessary)')
50+
try { execSync('mkcert -install', { stdio: 'inherit' }) } catch (e) { /* ignore */ }
51+
const mkcertCmd = `mkcert -cert-file "${certFile}" -key-file "${keyFile}" ${hosts.map(h => '"' + h + '"').join(' ')}`
52+
run(mkcertCmd)
53+
console.log('Created certs:')
54+
console.log(' ', certFile)
55+
console.log(' ', keyFile)
56+
process.exit(0)
57+
} catch (e) {
58+
console.log('mkcert not available — falling back to OpenSSL self-signed cert (NOT trusted automatically)')
59+
}
60+
61+
62+
// Fallback: openssl (self-signed, will trigger browser warnings unless imported into trust stores)
63+
try {
64+
const subj = '/CN=localhost'
65+
const opensslCmd = `openssl req -x509 -newkey rsa:2048 -nodes -keyout "${keyFile}" -out "${certFile}" -days 365 -subj "${subj}"`
66+
run(opensslCmd)
67+
console.log('Created self-signed certs:')
68+
console.log(' ', certFile)
69+
console.log(' ', keyFile)
70+
console.log('\nNote: This self-signed certificate will NOT be trusted by browsers automatically. Use mkcert if you want a trusted cert. See HTTPS_SETUP.md for instructions.')
71+
process.exit(0)
72+
} catch (err) {
73+
console.error('Failed to create certificates. Make sure you have `mkcert` or `openssl` installed.\nError: ', err && err.message)
74+
process.exit(1)
75+
}

vite.config.js

Lines changed: 110 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,95 +1,117 @@
11
import { defineConfig } from 'vite'
22
import react from '@vitejs/plugin-react'
33
import { VitePWA } from 'vite-plugin-pwa'
4+
import fs from 'fs'
5+
import path from 'path'
6+
7+
const certDir = path.resolve(__dirname, 'certs')
8+
const certPath = path.join(certDir, 'localhost.pem')
9+
const keyPath = path.join(certDir, 'localhost-key.pem')
10+
11+
let httpsOptions = false
12+
try {
13+
if (fs.existsSync(certPath) && fs.existsSync(keyPath)) {
14+
httpsOptions = {
15+
cert: fs.readFileSync(certPath),
16+
key: fs.readFileSync(keyPath)
17+
}
18+
console.log('[vite] Using HTTPS certs for dev server')
19+
} else {
20+
console.warn('[vite] No HTTPS certs found — run `npm run generate-cert` to create them')
21+
}
22+
} catch (e) {
23+
console.warn('[vite] Error reading HTTPS certs:', e.message)
24+
}
425

526
export default defineConfig({
6-
base: process.env.VITE_BASE_PATH || '/',
7-
plugins: [
8-
react(),
9-
VitePWA({
10-
registerType: 'autoUpdate',
11-
workbox: {
12-
globPatterns: ['**/*.{js,css,html,ico,png,svg,woff2}'],
13-
navigateFallback: '/offline.html',
14-
navigateFallbackDenylist: [/^\/api\//],
15-
runtimeCaching: [
16-
{
17-
urlPattern: /^https:\/\/0\.peerjs\.com\//,
18-
handler: 'NetworkFirst',
19-
options: {
20-
cacheName: 'peerjs-cache',
21-
expiration: {
22-
maxEntries: 10,
23-
maxAgeSeconds: 60 * 60 * 24 // 24 hours
24-
}
25-
}
26-
},
27-
{
28-
urlPattern: /^https:\/\/api\.qrserver\.com\//,
29-
handler: 'CacheFirst',
30-
options: {
31-
cacheName: 'qr-cache',
32-
expiration: {
33-
maxEntries: 50,
34-
maxAgeSeconds: 60 * 60 * 24 * 7 // 7 days
35-
}
36-
}
37-
}
38-
]
39-
},
40-
manifest: {
41-
name: 'Peer P2P Voice Chat',
42-
short_name: 'PeerChat',
43-
description: 'Local Wi-Fi P2P voice chat using WebRTC (PeerJS)',
44-
theme_color: '#0f172a',
45-
background_color: '#0f172a',
46-
display: 'standalone',
47-
orientation: 'portrait-primary',
48-
scope: '/',
49-
start_url: '/',
50-
lang: 'en',
51-
categories: ['communication', 'social'],
52-
icons: [
53-
{
54-
src: 'pwa-192x192.png',
55-
sizes: '192x192',
56-
type: 'image/png',
57-
purpose: 'any maskable'
58-
},
59-
{
60-
src: 'pwa-512x512.png',
61-
sizes: '512x512',
62-
type: 'image/png',
63-
purpose: 'any maskable'
64-
},
65-
{
66-
src: 'apple-touch-icon.png',
67-
sizes: '180x180',
68-
type: 'image/png'
69-
}
70-
],
71-
shortcuts: [
72-
{
73-
name: 'Start Voice Chat',
74-
short_name: 'Voice Chat',
75-
description: 'Start a new voice chat session',
76-
url: '/?action=call',
77-
icons: [
78-
{
79-
src: 'pwa-192x192.png',
80-
sizes: '192x192'
81-
}
82-
]
83-
}
84-
]
85-
},
86-
devOptions: {
87-
enabled: true
27+
base: process.env.VITE_BASE_PATH || '/',
28+
plugins: [
29+
react(),
30+
VitePWA({
31+
registerType: 'autoUpdate',
32+
workbox: {
33+
globPatterns: ['**/*.{js,css,html,ico,png,svg,woff2}'],
34+
navigateFallback: '/offline.html',
35+
navigateFallbackDenylist: [/^\\/api\\//],
36+
runtimeCaching: [
37+
{
38+
urlPattern: /^https:\\/\\/0\\.peerjs\\.com\\//,
39+
handler: 'NetworkFirst',
40+
options: {
41+
cacheName: 'peerjs-cache',
42+
expiration: {
43+
maxEntries: 10,
44+
maxAgeSeconds: 60 * 60 * 24
45+
}
8846
}
89-
})
90-
],
91-
server: {
92-
host: true,
93-
port: 5173
94-
}
47+
},
48+
{
49+
urlPattern: /^https:\\/\\/api\\.qrserver\\.com\\//,
50+
handler: 'CacheFirst',
51+
options: {
52+
cacheName: 'qr-cache',
53+
expiration: {
54+
maxEntries: 50,
55+
maxAgeSeconds: 60 * 60 * 24 * 7
56+
}
57+
}
58+
}
59+
]
60+
},
61+
manifest: {
62+
name: 'Peer P2P Voice Chat',
63+
short_name: 'PeerChat',
64+
description: 'Local Wi-Fi P2P voice chat using WebRTC (PeerJS)',
65+
theme_color: '#0f172a',
66+
background_color: '#0f172a',
67+
display: 'standalone',
68+
orientation: 'portrait-primary',
69+
scope: '/',
70+
start_url: '/',
71+
lang: 'en',
72+
categories: ['communication', 'social'],
73+
icons: [
74+
{
75+
src: 'pwa-192x192.png',
76+
sizes: '192x192',
77+
type: 'image/png',
78+
purpose: 'any maskable'
79+
},
80+
{
81+
src: 'pwa-512x512.png',
82+
sizes: '512x512',
83+
type: 'image/png',
84+
purpose: 'any maskable'
85+
},
86+
{
87+
src: 'apple-touch-icon.png',
88+
sizes: '180x180',
89+
type: 'image/png'
90+
}
91+
],
92+
shortcuts: [
93+
{
94+
name: 'Start Voice Chat',
95+
short_name: 'Voice Chat',
96+
description: 'Start a new voice chat session',
97+
url: '/?action=call',
98+
icons: [
99+
{
100+
src: 'pwa-192x192.png',
101+
sizes: '192x192'
102+
}
103+
]
104+
}
105+
]
106+
},
107+
devOptions: {
108+
enabled: true
109+
}
110+
})
111+
],
112+
server: {
113+
host: true,
114+
port: 5173,
115+
https: httpsOptions
116+
}
95117
})

0 commit comments

Comments
 (0)