chore: replace Caddy with Portless for local HTTPS proxy (#258)
## Summary - Replace Caddy reverse proxy with [Portless](https://portless.sh) for local HTTPS, eliminating manual cert generation and `/etc/hosts` editing - Two URL strategies coexist: `composer run dev` uses worktree-aware URLs (`https://<branch>.dev.whisper.money.localhost`), `whispermoney start` uses a fixed alias (`https://whisper.money.localhost`) - Remove Caddyfile, `docker/caddy/` directory, caddy service from `compose.yaml`, and cert-related `.gitignore` entries - Simplify `vite.config.ts` by removing caddy cert detection block (Vite stays on plain HTTP since browsers treat localhost as secure context) - Overhaul `public/setup.sh` to use `portless trust`, `portless proxy start`, and `portless alias` instead of SSL cert generation and hosts file editing
This commit is contained in:
parent
83f7e83a13
commit
259a9a9712
|
|
@ -2,7 +2,7 @@ APP_NAME="Whisper Money"
|
||||||
APP_ENV=local
|
APP_ENV=local
|
||||||
APP_KEY=
|
APP_KEY=
|
||||||
APP_DEBUG=true
|
APP_DEBUG=true
|
||||||
APP_URL=https://whisper.money.local
|
APP_URL=https://whisper.money.localhost
|
||||||
|
|
||||||
APP_LOCALE=en
|
APP_LOCALE=en
|
||||||
APP_FALLBACK_LOCALE=en
|
APP_FALLBACK_LOCALE=en
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,5 @@ yarn-error.log
|
||||||
/.vscode
|
/.vscode
|
||||||
/.zed
|
/.zed
|
||||||
.php-cs-fixer.cache
|
.php-cs-fixer.cache
|
||||||
/docker/caddy/certs/*.pem
|
|
||||||
/docker/caddy/certs/*-key.pem
|
|
||||||
.claude/settings.local.json
|
.claude/settings.local.json
|
||||||
.php-version
|
.php-version
|
||||||
|
|
|
||||||
16
Caddyfile
16
Caddyfile
|
|
@ -1,16 +0,0 @@
|
||||||
whisper.money.local {
|
|
||||||
# Use mkcert certificates (generated by setup script)
|
|
||||||
# These certificates are automatically trusted by browsers
|
|
||||||
tls /etc/caddy/certs/whisper.money.local.pem /etc/caddy/certs/whisper.money.local-key.pem
|
|
||||||
|
|
||||||
reverse_proxy host.docker.internal:8000
|
|
||||||
|
|
||||||
header {
|
|
||||||
-Server
|
|
||||||
X-Content-Type-Options "nosniff"
|
|
||||||
X-Frame-Options "DENY"
|
|
||||||
X-XSS-Protection "1; mode=block"
|
|
||||||
}
|
|
||||||
|
|
||||||
encode zstd gzip
|
|
||||||
}
|
|
||||||
|
|
@ -51,7 +51,7 @@ The easiest way to get started is using our automated setup script:
|
||||||
bash <(curl -fsSL https://whisper.money/setup.sh)
|
bash <(curl -fsSL https://whisper.money/setup.sh)
|
||||||
```
|
```
|
||||||
|
|
||||||
After installation, just visit **<https://whisper.money.local>** in your browser.
|
After installation, just visit **<https://whisper.money.localhost>** in your browser.
|
||||||
|
|
||||||
### Manual Setup
|
### Manual Setup
|
||||||
|
|
||||||
|
|
@ -100,12 +100,12 @@ composer run dev
|
||||||
|
|
||||||
This will concurrently start:
|
This will concurrently start:
|
||||||
|
|
||||||
- PHP development server
|
- PHP development server (via [Portless](https://portless.sh) HTTPS proxy)
|
||||||
- Queue worker
|
- Queue worker
|
||||||
- Log viewer (Pail)
|
- Log viewer (Pail)
|
||||||
- Vite dev server
|
- Vite dev server
|
||||||
|
|
||||||
The application will be available at **<https://whisper.money.local>** or **<http://localhost:8000>** (direct PHP server).
|
The application will be available at **<https://dev.whisper.money.localhost>**. In git worktrees, the branch name is automatically prepended (e.g. `https://fix-ui.dev.whisper.money.localhost`).
|
||||||
|
|
||||||
## Running with Docker (Production Image)
|
## Running with Docker (Production Image)
|
||||||
|
|
||||||
|
|
|
||||||
3
bun.lock
3
bun.lock
|
|
@ -75,6 +75,7 @@
|
||||||
"eslint-plugin-react-hooks": "^7.0.1",
|
"eslint-plugin-react-hooks": "^7.0.1",
|
||||||
"jsdom": "^25.0.1",
|
"jsdom": "^25.0.1",
|
||||||
"playwright": "^1.58.2",
|
"playwright": "^1.58.2",
|
||||||
|
"portless": "^0.9.2",
|
||||||
"prettier": "^3.8.1",
|
"prettier": "^3.8.1",
|
||||||
"prettier-plugin-organize-imports": "^4.3.0",
|
"prettier-plugin-organize-imports": "^4.3.0",
|
||||||
"prettier-plugin-tailwindcss": "^0.6.14",
|
"prettier-plugin-tailwindcss": "^0.6.14",
|
||||||
|
|
@ -1459,6 +1460,8 @@
|
||||||
|
|
||||||
"playwright-core": ["playwright-core@1.58.2", "", { "bin": { "playwright-core": "cli.js" } }, "sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg=="],
|
"playwright-core": ["playwright-core@1.58.2", "", { "bin": { "playwright-core": "cli.js" } }, "sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg=="],
|
||||||
|
|
||||||
|
"portless": ["portless@0.9.2", "", { "os": [ "linux", "win32", "darwin", ], "bin": { "portless": "dist/cli.js" } }, "sha512-sB8orlek3wrBwzZhggRAfEzplS+3srYBfSlArl6ZqAenFvK1hYEI2Rb1W+oFmxcrKCDn5WomNMVWDijio8ds9w=="],
|
||||||
|
|
||||||
"possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="],
|
"possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="],
|
||||||
|
|
||||||
"postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="],
|
"postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="],
|
||||||
|
|
|
||||||
20
compose.yaml
20
compose.yaml
|
|
@ -1,20 +1,4 @@
|
||||||
services:
|
services:
|
||||||
caddy:
|
|
||||||
image: 'caddy:latest'
|
|
||||||
ports:
|
|
||||||
- '80:80'
|
|
||||||
- '443:443'
|
|
||||||
- '443:443/udp'
|
|
||||||
volumes:
|
|
||||||
- './Caddyfile:/etc/caddy/Caddyfile:ro'
|
|
||||||
- './docker/caddy/certs:/etc/caddy/certs:ro'
|
|
||||||
- 'caddy_data:/data'
|
|
||||||
- 'caddy_config:/config'
|
|
||||||
networks:
|
|
||||||
- sail
|
|
||||||
extra_hosts:
|
|
||||||
- 'host.docker.internal:host-gateway'
|
|
||||||
restart: unless-stopped
|
|
||||||
mysql:
|
mysql:
|
||||||
image: 'mysql/mysql-server:8.0'
|
image: 'mysql/mysql-server:8.0'
|
||||||
ports:
|
ports:
|
||||||
|
|
@ -97,7 +81,3 @@ volumes:
|
||||||
driver: local
|
driver: local
|
||||||
sail-redis:
|
sail-redis:
|
||||||
driver: local
|
driver: local
|
||||||
caddy_data:
|
|
||||||
driver: local
|
|
||||||
caddy_config:
|
|
||||||
driver: local
|
|
||||||
|
|
|
||||||
|
|
@ -61,12 +61,12 @@
|
||||||
],
|
],
|
||||||
"dev": [
|
"dev": [
|
||||||
"Composer\\Config::disableProcessTimeout",
|
"Composer\\Config::disableProcessTimeout",
|
||||||
"npx concurrently -c \"#93c5fd,#c4b5fd,#fb7185,#fdba74,#2dd4bf\" \"php artisan serve\" \"php artisan queue:listen --tries=1 --queue=emails\" \"php artisan pail --timeout=0\" \"bun run dev\" \"stripe listen --forward-to https://whisper.money.local/stripe/webhook\" --names=server,emails-queue,logs,vite,stripe"
|
"npx concurrently -c \"#93c5fd,#c4b5fd,#fb7185,#fdba74,#2dd4bf\" \"npx portless run --name dev.whisper.money --app-port 8000 php artisan serve\" \"php artisan queue:listen --tries=1 --queue=emails\" \"php artisan pail --timeout=0\" \"bun run dev\" \"stripe listen --forward-to https://dev.whisper.money.localhost/stripe/webhook\" --names=server,emails-queue,logs,vite,stripe"
|
||||||
],
|
],
|
||||||
"dev:ssr": [
|
"dev:ssr": [
|
||||||
"bun run build:ssr",
|
"bun run build:ssr",
|
||||||
"Composer\\Config::disableProcessTimeout",
|
"Composer\\Config::disableProcessTimeout",
|
||||||
"npx concurrently -c \"#93c5fd,#c4b5fd,#fb7185,#fdba74,#2dd4bf\" \"php artisan serve\" \"php artisan queue:listen --tries=1 --queue=emails\" \"php artisan pail --timeout=0\" \"php artisan inertia:start-ssr --runtime=bun\" --names=server,emails-queue,logs,ssr,stripe --kill-others"
|
"npx concurrently -c \"#93c5fd,#c4b5fd,#fb7185,#fdba74,#2dd4bf\" \"npx portless run --name dev.whisper.money --app-port 8000 php artisan serve\" \"php artisan queue:listen --tries=1 --queue=emails\" \"php artisan pail --timeout=0\" \"php artisan inertia:start-ssr --runtime=bun\" --names=server,emails-queue,logs,ssr,stripe --kill-others"
|
||||||
],
|
],
|
||||||
"test": [
|
"test": [
|
||||||
"@php artisan config:clear --ansi",
|
"@php artisan config:clear --ansi",
|
||||||
|
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
certs_dir="$(dirname "$0")/certs"
|
|
||||||
domain="whisper.money.local"
|
|
||||||
cert_file="${certs_dir}/${domain}.pem"
|
|
||||||
key_file="${certs_dir}/${domain}-key.pem"
|
|
||||||
|
|
||||||
mkdir -p "$certs_dir"
|
|
||||||
|
|
||||||
if command -v mkcert &> /dev/null; then
|
|
||||||
if [ ! -f "$(mkcert -CAROOT)/rootCA.pem" ]; then
|
|
||||||
echo "Installing local CA..."
|
|
||||||
mkcert -install
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Generating certificates for ${domain}..."
|
|
||||||
mkcert -cert-file "$cert_file" -key-file "$key_file" "$domain" "*.${domain}"
|
|
||||||
echo "Certificates generated successfully!"
|
|
||||||
echo "Files created:"
|
|
||||||
echo " - ${cert_file}"
|
|
||||||
echo " - ${key_file}"
|
|
||||||
elif command -v openssl &> /dev/null; then
|
|
||||||
echo "Creating self-signed certificates (browser will show a warning)..."
|
|
||||||
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
|
|
||||||
-keyout "$key_file" \
|
|
||||||
-out "$cert_file" \
|
|
||||||
-subj "/CN=${domain}/O=Development/C=US" \
|
|
||||||
-addext "subjectAltName=DNS:${domain},DNS:*.${domain},IP:127.0.0.1" \
|
|
||||||
2>/dev/null
|
|
||||||
|
|
||||||
chmod 644 "$cert_file"
|
|
||||||
chmod 600 "$key_file"
|
|
||||||
echo "Self-signed certificates created"
|
|
||||||
echo "Note: Your browser will show a security warning."
|
|
||||||
else
|
|
||||||
echo "Error: Neither mkcert nor openssl is available"
|
|
||||||
echo "Please install mkcert (recommended) or openssl"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
@ -34,6 +34,7 @@
|
||||||
"eslint-plugin-react-hooks": "^7.0.1",
|
"eslint-plugin-react-hooks": "^7.0.1",
|
||||||
"jsdom": "^25.0.1",
|
"jsdom": "^25.0.1",
|
||||||
"playwright": "^1.58.2",
|
"playwright": "^1.58.2",
|
||||||
|
"portless": "^0.9.2",
|
||||||
"prettier": "^3.8.1",
|
"prettier": "^3.8.1",
|
||||||
"prettier-plugin-organize-imports": "^4.3.0",
|
"prettier-plugin-organize-imports": "^4.3.0",
|
||||||
"prettier-plugin-tailwindcss": "^0.6.14",
|
"prettier-plugin-tailwindcss": "^0.6.14",
|
||||||
|
|
|
||||||
308
public/setup.sh
308
public/setup.sh
|
|
@ -318,19 +318,6 @@ find_available_port() {
|
||||||
check_and_configure_ports() {
|
check_and_configure_ports() {
|
||||||
echo -e "${BLUE}Checking port availability...${NC}"
|
echo -e "${BLUE}Checking port availability...${NC}"
|
||||||
|
|
||||||
# Check required ports (Caddy and PHP - these cannot be changed)
|
|
||||||
if ! is_port_available 80; then
|
|
||||||
echo -e "${RED}Port 80 is already in use. Caddy requires this port.${NC}"
|
|
||||||
echo -e "${YELLOW}Please stop the service using port 80 and try again.${NC}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! is_port_available 443; then
|
|
||||||
echo -e "${RED}Port 443 is already in use. Caddy requires this port.${NC}"
|
|
||||||
echo -e "${YELLOW}Please stop the service using port 443 and try again.${NC}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! is_port_available 8000; then
|
if ! is_port_available 8000; then
|
||||||
echo -e "${RED}Port 8000 is already in use. PHP requires this port.${NC}"
|
echo -e "${RED}Port 8000 is already in use. PHP requires this port.${NC}"
|
||||||
echo -e "${YELLOW}Please stop the service using port 8000 and try again.${NC}"
|
echo -e "${YELLOW}Please stop the service using port 8000 and try again.${NC}"
|
||||||
|
|
@ -553,232 +540,47 @@ wait_for_service() {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
# Update /etc/hosts file
|
# Setup portless for HTTPS reverse proxy
|
||||||
update_hosts_file() {
|
setup_portless() {
|
||||||
local hostname="whisper.money.local"
|
|
||||||
local ip="127.0.0.1"
|
|
||||||
local hosts_line="${ip} ${hostname}"
|
|
||||||
local hosts_file="/etc/hosts"
|
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
||||||
echo -e "${YELLOW}Hosts File Update${NC}"
|
echo -e "${YELLOW}HTTPS Setup (Portless)${NC}"
|
||||||
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
||||||
echo ""
|
echo ""
|
||||||
echo -e "${BLUE}To access your application at ${GREEN}https://${hostname}${NC}${BLUE}, we need to${NC}"
|
|
||||||
echo -e "${BLUE}add an entry to your system's hosts file (${hosts_file}).${NC}"
|
|
||||||
echo ""
|
|
||||||
echo -e "${YELLOW}What we'll do:${NC}"
|
|
||||||
echo -e " • Add the line: ${GREEN}${hosts_line}${NC}"
|
|
||||||
echo -e " • This maps ${hostname} to your local machine (127.0.0.1)"
|
|
||||||
echo ""
|
|
||||||
echo -e "${YELLOW}Why we need sudo access:${NC}"
|
|
||||||
echo -e " • The hosts file is a system file that requires administrator privileges"
|
|
||||||
echo -e " • We'll only add the entry if it doesn't already exist (idempotent)"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Check if the line already exists
|
if ! command_exists npx; then
|
||||||
if grep -q "${hostname}" "${hosts_file}" 2>/dev/null; then
|
echo -e "${RED}npx is not available. Portless requires Node.js.${NC}"
|
||||||
if grep -q "${hosts_line}" "${hosts_file}" 2>/dev/null; then
|
echo -e "${YELLOW}Skipping HTTPS setup. The app will be available at http://localhost:8000${NC}"
|
||||||
echo -e "${GREEN}✓ The hosts entry already exists. No changes needed.${NC}"
|
|
||||||
return 0
|
|
||||||
else
|
|
||||||
echo -e "${YELLOW}⚠ Found a different entry for ${hostname} in ${hosts_file}${NC}"
|
|
||||||
echo -e "${YELLOW} Please review it manually.${NC}"
|
|
||||||
echo ""
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
read -p "Would you like us to update the hosts file automatically? (y/n) " -n 1 -r
|
|
||||||
echo ""
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
||||||
echo -e "${YELLOW}Updating hosts file (sudo access required)...${NC}"
|
|
||||||
|
|
||||||
# Use sudo to add the line if it doesn't exist
|
|
||||||
if sudo sh -c "grep -q '${hosts_line}' ${hosts_file} || echo '${hosts_line}' >> ${hosts_file}"; then
|
|
||||||
echo -e "${GREEN}✓ Successfully updated ${hosts_file}${NC}"
|
|
||||||
echo -e "${GREEN} Added: ${hosts_line}${NC}"
|
|
||||||
return 0
|
|
||||||
else
|
|
||||||
echo -e "${RED}✗ Failed to update ${hosts_file}${NC}"
|
|
||||||
echo -e "${YELLOW} You'll need to add it manually.${NC}"
|
|
||||||
show_manual_hosts_instructions
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo -e "${YELLOW}Hosts file update skipped.${NC}"
|
|
||||||
show_manual_hosts_instructions
|
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
}
|
|
||||||
|
|
||||||
# Setup SSL certificates using mkcert for transparent trust
|
# Trust the portless CA (one-time setup, auto-elevates with sudo)
|
||||||
setup_ssl_certificates() {
|
echo -e "${YELLOW}Setting up portless HTTPS certificates...${NC}"
|
||||||
local certs_dir="docker/caddy/certs"
|
if npx portless trust 2>/dev/null; then
|
||||||
local domain="whisper.money.local"
|
echo -e "${GREEN}✓ Portless CA trusted${NC}"
|
||||||
local cert_file="${certs_dir}/${domain}.pem"
|
|
||||||
local key_file="${certs_dir}/${domain}-key.pem"
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
||||||
echo -e "${YELLOW}SSL Certificate Setup${NC}"
|
|
||||||
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Check if certificates already exist
|
|
||||||
if [ -f "$cert_file" ] && [ -f "$key_file" ]; then
|
|
||||||
echo -e "${GREEN}✓ SSL certificates already exist${NC}"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check if mkcert is installed
|
|
||||||
if ! command_exists mkcert; then
|
|
||||||
echo -e "${YELLOW}mkcert is not installed. It's needed to generate trusted SSL certificates.${NC}"
|
|
||||||
echo ""
|
|
||||||
echo -e "${BLUE}mkcert creates locally-trusted certificates that browsers automatically trust.${NC}"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
|
||||||
echo -e "${YELLOW}Install mkcert:${NC}"
|
|
||||||
echo -e " ${GREEN}brew install mkcert${NC}"
|
|
||||||
echo -e " ${GREEN}brew install nss${NC} # For Firefox support"
|
|
||||||
echo ""
|
|
||||||
read -p "Would you like to install mkcert now? (y/n) " -n 1 -r
|
|
||||||
echo ""
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
||||||
if command_exists brew; then
|
|
||||||
echo -e "${YELLOW}Installing mkcert...${NC}"
|
|
||||||
brew install mkcert nss
|
|
||||||
echo -e "${GREEN}✓ mkcert installed${NC}"
|
|
||||||
else
|
|
||||||
echo -e "${RED}Homebrew is not installed. Please install mkcert manually:${NC}"
|
|
||||||
echo -e " ${YELLOW}brew install mkcert nss${NC}"
|
|
||||||
echo ""
|
|
||||||
echo -e "${YELLOW}Or visit: https://github.com/FiloSottile/mkcert#installation${NC}"
|
|
||||||
create_fallback_certificates
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo -e "${YELLOW}Using fallback self-signed certificates...${NC}"
|
|
||||||
create_fallback_certificates
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo -e "${YELLOW}Install mkcert:${NC}"
|
|
||||||
echo -e " ${GREEN}sudo apt install libnss3-tools${NC} # Debian/Ubuntu"
|
|
||||||
echo -e " ${GREEN}wget -O /tmp/mkcert https://github.com/FiloSottile/mkcert/releases/latest/download/mkcert-v1.4.4-linux-amd64${NC}"
|
|
||||||
echo -e " ${GREEN}chmod +x /tmp/mkcert && sudo mv /tmp/mkcert /usr/local/bin/mkcert${NC}"
|
|
||||||
echo ""
|
|
||||||
echo -e "${YELLOW}Or visit: https://github.com/FiloSottile/mkcert#installation${NC}"
|
|
||||||
echo ""
|
|
||||||
read -p "Continue with fallback self-signed certificates? (y/n) " -n 1 -r
|
|
||||||
echo ""
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
||||||
echo -e "${YELLOW}Please install mkcert and run the setup again.${NC}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
create_fallback_certificates
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Install local CA if not already installed
|
|
||||||
if [ ! -f "$(mkcert -CAROOT)/rootCA.pem" ]; then
|
|
||||||
echo -e "${YELLOW}Installing mkcert local CA (requires sudo)...${NC}"
|
|
||||||
mkcert -install
|
|
||||||
echo -e "${GREEN}✓ Local CA installed${NC}"
|
|
||||||
else
|
else
|
||||||
echo -e "${GREEN}✓ Local CA already installed${NC}"
|
echo -e "${YELLOW}⚠ Could not trust portless CA automatically.${NC}"
|
||||||
|
echo -e "${YELLOW} You can run 'npx portless trust' manually later.${NC}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Create certs directory
|
# Start the portless proxy if not already running
|
||||||
mkdir -p "$certs_dir"
|
echo -e "${YELLOW}Starting portless proxy...${NC}"
|
||||||
|
if npx portless proxy start 2>/dev/null; then
|
||||||
# Generate certificate
|
echo -e "${GREEN}✓ Portless proxy running${NC}"
|
||||||
echo -e "${YELLOW}Generating SSL certificate for ${domain}...${NC}"
|
|
||||||
if mkcert -cert-file "$cert_file" -key-file "$key_file" "$domain" "*.${domain}"; then
|
|
||||||
echo -e "${GREEN}✓ SSL certificate generated successfully${NC}"
|
|
||||||
echo -e "${GREEN} Certificate: ${cert_file}${NC}"
|
|
||||||
echo -e "${GREEN} Key: ${key_file}${NC}"
|
|
||||||
echo ""
|
|
||||||
echo -e "${BLUE}Your browser will automatically trust this certificate!${NC}"
|
|
||||||
return 0
|
|
||||||
else
|
else
|
||||||
echo -e "${RED}✗ Failed to generate certificate${NC}"
|
echo -e "${YELLOW}⚠ Could not start portless proxy automatically.${NC}"
|
||||||
create_fallback_certificates
|
echo -e "${YELLOW} It may already be running, or you can start it with 'npx portless proxy start'.${NC}"
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Create fallback self-signed certificates
|
|
||||||
create_fallback_certificates() {
|
|
||||||
local certs_dir="docker/caddy/certs"
|
|
||||||
local domain="whisper.money.local"
|
|
||||||
local cert_file="${certs_dir}/${domain}.pem"
|
|
||||||
local key_file="${certs_dir}/${domain}-key.pem"
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo -e "${YELLOW}Creating self-signed certificates (browser will show a warning)...${NC}"
|
|
||||||
|
|
||||||
mkdir -p "$certs_dir"
|
|
||||||
|
|
||||||
# Check if openssl is available
|
|
||||||
if command_exists openssl; then
|
|
||||||
# Create certificate with proper SAN extension
|
|
||||||
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
|
|
||||||
-keyout "$key_file" \
|
|
||||||
-out "$cert_file" \
|
|
||||||
-subj "/CN=${domain}/O=Development/C=US" \
|
|
||||||
-addext "subjectAltName=DNS:${domain},DNS:*.${domain},IP:127.0.0.1" \
|
|
||||||
2>/dev/null
|
|
||||||
|
|
||||||
if [ -f "$cert_file" ] && [ -f "$key_file" ]; then
|
|
||||||
# Set proper permissions
|
|
||||||
chmod 644 "$cert_file"
|
|
||||||
chmod 600 "$key_file"
|
|
||||||
echo -e "${GREEN}✓ Self-signed certificates created${NC}"
|
|
||||||
echo -e "${YELLOW} Note: Your browser will show a security warning.${NC}"
|
|
||||||
echo -e "${YELLOW} Click 'Advanced' → 'Proceed to ${domain}' to continue.${NC}"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo -e "${RED}✗ Could not create certificates${NC}"
|
# Register the fixed alias for whisper.money
|
||||||
echo -e "${YELLOW} Please install mkcert or openssl to generate certificates.${NC}"
|
echo -e "${YELLOW}Registering HTTPS route...${NC}"
|
||||||
return 1
|
if npx portless alias whisper.money 8000 --force 2>/dev/null; then
|
||||||
}
|
echo -e "${GREEN}✓ https://whisper.money.localhost → localhost:8000${NC}"
|
||||||
|
else
|
||||||
|
echo -e "${YELLOW}⚠ Could not register portless alias.${NC}"
|
||||||
|
echo -e "${YELLOW} You can run 'npx portless alias whisper.money 8000' manually.${NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
# Show manual hosts file instructions
|
|
||||||
show_manual_hosts_instructions() {
|
|
||||||
local hostname="whisper.money.local"
|
|
||||||
local hosts_line="127.0.0.1 ${hostname}"
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo -e "${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
||||||
echo -e "${YELLOW}Manual Hosts File Update${NC}"
|
|
||||||
echo -e "${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
||||||
echo ""
|
|
||||||
echo -e "${BLUE}To access your application, please add this line to ${YELLOW}/etc/hosts${NC}${BLUE}:${NC}"
|
|
||||||
echo ""
|
|
||||||
echo -e " ${GREEN}${hosts_line}${NC}"
|
|
||||||
echo ""
|
|
||||||
echo -e "${YELLOW}Instructions:${NC}"
|
|
||||||
echo -e " 1. Open ${YELLOW}/etc/hosts${NC} with a text editor (requires sudo):"
|
|
||||||
echo -e " ${YELLOW}sudo nano /etc/hosts${NC} ${BLUE}(or use your preferred editor)${NC}"
|
|
||||||
echo ""
|
|
||||||
echo -e " 2. Add the line at the end of the file:"
|
|
||||||
echo -e " ${GREEN}${hosts_line}${NC}"
|
|
||||||
echo ""
|
|
||||||
echo -e " 3. Save and close the file"
|
|
||||||
echo ""
|
|
||||||
echo -e "${YELLOW}Note:${NC} If the line already exists, you can skip this step."
|
|
||||||
echo ""
|
echo ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -800,11 +602,25 @@ start_services() {
|
||||||
wait_for_service "php"
|
wait_for_service "php"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo -e "${GREEN}All services are running!${NC}"
|
# Register portless alias for HTTPS access
|
||||||
|
if command_exists npx; then
|
||||||
|
npx portless proxy start 2>/dev/null || true
|
||||||
|
npx portless alias whisper.money 8000 --force 2>/dev/null || true
|
||||||
|
echo -e "${GREEN}All services are running!${NC}"
|
||||||
|
echo -e " ${GREEN}Visit: https://whisper.money.localhost${NC}"
|
||||||
|
else
|
||||||
|
echo -e "${GREEN}All services are running!${NC}"
|
||||||
|
echo -e " ${GREEN}Visit: http://localhost:8000${NC}"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Stop Docker services
|
# Stop Docker services
|
||||||
stop_services() {
|
stop_services() {
|
||||||
|
# Remove portless alias
|
||||||
|
if command_exists npx; then
|
||||||
|
npx portless alias --remove whisper.money 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
echo -e "${BLUE}Stopping Docker services...${NC}"
|
echo -e "${BLUE}Stopping Docker services...${NC}"
|
||||||
docker compose down
|
docker compose down
|
||||||
echo -e "${GREEN}Services stopped.${NC}"
|
echo -e "${GREEN}Services stopped.${NC}"
|
||||||
|
|
@ -839,11 +655,11 @@ install() {
|
||||||
|
|
||||||
# Update APP_URL if needed
|
# Update APP_URL if needed
|
||||||
if grep -q "APP_URL=https://whispermoney.test" .env 2>/dev/null || grep -q "APP_URL=$" .env 2>/dev/null; then
|
if grep -q "APP_URL=https://whispermoney.test" .env 2>/dev/null || grep -q "APP_URL=$" .env 2>/dev/null; then
|
||||||
echo -e "${YELLOW}Updating APP_URL to https://whisper.money.local...${NC}"
|
echo -e "${YELLOW}Updating APP_URL to https://whisper.money.localhost...${NC}"
|
||||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||||
sed -i '' 's|APP_URL=.*|APP_URL=https://whisper.money.local|g' .env
|
sed -i '' 's|APP_URL=.*|APP_URL=https://whisper.money.localhost|g' .env
|
||||||
else
|
else
|
||||||
sed -i 's|APP_URL=.*|APP_URL=https://whisper.money.local|g' .env
|
sed -i 's|APP_URL=.*|APP_URL=https://whisper.money.localhost|g' .env
|
||||||
fi
|
fi
|
||||||
echo -e "${GREEN}APP_URL updated.${NC}"
|
echo -e "${GREEN}APP_URL updated.${NC}"
|
||||||
else
|
else
|
||||||
|
|
@ -877,10 +693,6 @@ install() {
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# Update hosts file early so the domain resolves before services start
|
|
||||||
update_hosts_file
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Install Composer dependencies BEFORE starting Docker services
|
# Install Composer dependencies BEFORE starting Docker services
|
||||||
# (Docker Compose mounts files from vendor/laravel/sail that need to exist)
|
# (Docker Compose mounts files from vendor/laravel/sail that need to exist)
|
||||||
echo -e "${BLUE}Installing Composer dependencies...${NC}"
|
echo -e "${BLUE}Installing Composer dependencies...${NC}"
|
||||||
|
|
@ -888,16 +700,12 @@ install() {
|
||||||
echo -e "${GREEN}Composer dependencies installed.${NC}"
|
echo -e "${GREEN}Composer dependencies installed.${NC}"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# Setup SSL certificates before starting Caddy
|
|
||||||
setup_ssl_certificates
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Check and configure ports before starting Docker services
|
# Check and configure ports before starting Docker services
|
||||||
check_and_configure_ports
|
check_and_configure_ports
|
||||||
|
|
||||||
# Start Docker services (but don't start PHP yet - we'll start it after APP_KEY is generated)
|
# Start Docker services (but don't start PHP yet - we'll start it after APP_KEY is generated)
|
||||||
echo -e "${BLUE}Starting Docker services (excluding PHP for now)...${NC}"
|
echo -e "${BLUE}Starting Docker services (excluding PHP for now)...${NC}"
|
||||||
docker compose up -d mysql redis caddy mailhog
|
docker compose up -d mysql redis mailhog
|
||||||
|
|
||||||
wait_for_service "mysql"
|
wait_for_service "mysql"
|
||||||
wait_for_service "redis"
|
wait_for_service "redis"
|
||||||
|
|
@ -1058,6 +866,10 @@ install() {
|
||||||
fi
|
fi
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
|
# Setup portless for HTTPS access
|
||||||
|
setup_portless
|
||||||
|
echo ""
|
||||||
|
|
||||||
# Success message
|
# Success message
|
||||||
echo ""
|
echo ""
|
||||||
echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
||||||
|
|
@ -1066,29 +878,13 @@ install() {
|
||||||
echo ""
|
echo ""
|
||||||
echo -e "${BLUE}Your application is now running!${NC}"
|
echo -e "${BLUE}Your application is now running!${NC}"
|
||||||
echo ""
|
echo ""
|
||||||
echo -e " ${GREEN}Visit: https://whisper.money.local${NC}"
|
echo -e " ${GREEN}Visit: https://whisper.money.localhost${NC}"
|
||||||
echo ""
|
echo ""
|
||||||
|
echo -e "${GREEN}✓ Using portless for HTTPS (auto-trusted certificates)${NC}"
|
||||||
# Check if mkcert certificates are being used
|
|
||||||
if [ -f "docker/caddy/certs/whisper.money.local.pem" ]; then
|
|
||||||
echo -e "${GREEN}✓ Using trusted SSL certificates (mkcert)${NC}"
|
|
||||||
echo -e "${BLUE} Your browser will automatically trust the certificate!${NC}"
|
|
||||||
else
|
|
||||||
echo -e "${YELLOW}⚠ Using self-signed certificates${NC}"
|
|
||||||
echo -e "${BLUE} Your browser may show a security warning.${NC}"
|
|
||||||
echo -e "${BLUE} Click 'Advanced' → 'Proceed to whisper.money.local' to continue.${NC}"
|
|
||||||
echo ""
|
|
||||||
echo -e "${YELLOW}To avoid the warning, install mkcert and run setup again:${NC}"
|
|
||||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
|
||||||
echo -e " ${GREEN}brew install mkcert nss && mkcert -install${NC}"
|
|
||||||
else
|
|
||||||
echo -e " ${GREEN}# See: https://github.com/FiloSottile/mkcert#installation${NC}"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
echo ""
|
echo ""
|
||||||
echo -e "${BLUE}Services running:${NC}"
|
echo -e "${BLUE}Services running:${NC}"
|
||||||
echo -e " • PHP development server (port 8000)"
|
echo -e " • PHP development server (port 8000)"
|
||||||
echo -e " • Caddy reverse proxy (ports 80, 443)"
|
echo -e " • Portless HTTPS proxy (port 443)"
|
||||||
echo -e " • MySQL database"
|
echo -e " • MySQL database"
|
||||||
echo -e " • Redis cache"
|
echo -e " • Redis cache"
|
||||||
echo -e " • MailHog (email testing)"
|
echo -e " • MailHog (email testing)"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,3 @@
|
||||||
import fs from 'fs';
|
|
||||||
import path from 'path';
|
|
||||||
|
|
||||||
import { wayfinder } from '@laravel/vite-plugin-wayfinder';
|
import { wayfinder } from '@laravel/vite-plugin-wayfinder';
|
||||||
import { sentryVitePlugin } from '@sentry/vite-plugin';
|
import { sentryVitePlugin } from '@sentry/vite-plugin';
|
||||||
import tailwindcss from '@tailwindcss/vite';
|
import tailwindcss from '@tailwindcss/vite';
|
||||||
|
|
@ -12,18 +9,6 @@ export default defineConfig({
|
||||||
build: {
|
build: {
|
||||||
sourcemap: true,
|
sourcemap: true,
|
||||||
},
|
},
|
||||||
server: (() => {
|
|
||||||
const certPath = path.resolve(__dirname, 'docker/caddy/certs/whisper.money.local.pem');
|
|
||||||
const keyPath = path.resolve(__dirname, 'docker/caddy/certs/whisper.money.local-key.pem');
|
|
||||||
if (fs.existsSync(certPath) && fs.existsSync(keyPath)) {
|
|
||||||
return {
|
|
||||||
https: { cert: certPath, key: keyPath },
|
|
||||||
host: '0.0.0.0',
|
|
||||||
hmr: { host: 'whisper.money.local' },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
})(),
|
|
||||||
plugins: [
|
plugins: [
|
||||||
laravel({
|
laravel({
|
||||||
input: ['resources/css/app.css', 'resources/js/app.tsx'],
|
input: ['resources/css/app.css', 'resources/js/app.tsx'],
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue