diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 721d1e3..61ef0ca 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -24,21 +24,21 @@ jobs: docker run -d --name upstream -p 3000:80 nginx:alpine sleep 2 - - name: Create .env + - name: Create env file run: | - echo "DOMAIN=${{ env.DOMAIN }}" > .env - echo "HTTP_PORT=${{ env.HTTP_PORT }}" >> .env - echo "HTTPS_PORT=${{ env.HTTPS_PORT }}" >> .env - echo "UPSTREAM_URL=${{ env.UPSTREAM_URL }}" >> .env + echo "DOMAIN=${{ env.DOMAIN }}" > .env.${{ env.DOMAIN }} + echo "HTTP_PORT=${{ env.HTTP_PORT }}" >> .env.${{ env.DOMAIN }} + echo "HTTPS_PORT=${{ env.HTTPS_PORT }}" >> .env.${{ env.DOMAIN }} + echo "UPSTREAM_URL=${{ env.UPSTREAM_URL }}" >> .env.${{ env.DOMAIN }} - name: Add test domain to hosts run: echo "127.0.0.1 ${{ env.DOMAIN }}" | sudo tee -a /etc/hosts - name: Build images - run: docker compose build + run: docker compose --env-file .env.${{ env.DOMAIN }} build - name: Generate certificates - run: docker compose --profile setup run --rm mkcert + run: docker compose --env-file .env.${{ env.DOMAIN }} --profile setup run --rm mkcert - name: Verify certificates exist run: | @@ -47,13 +47,13 @@ jobs: test -f certs/${{ env.DOMAIN }}.rootCA.pem - name: Start proxy - run: docker compose up -d + run: docker compose --env-file .env.${{ env.DOMAIN }} up -d - name: Wait for Caddy to start run: sleep 3 - name: Check Caddy is running - run: docker compose ps --status running --services | grep -q '^caddy$' + run: docker compose --env-file .env.${{ env.DOMAIN }} ps --status running --services | grep -q '^caddy$' - name: Test HTTP redirect run: | @@ -64,10 +64,10 @@ jobs: curl -s --cacert certs/${{ env.DOMAIN }}.rootCA.pem https://${{ env.DOMAIN }}:${{ env.HTTPS_PORT }} | grep -q "nginx" - name: Show logs on failure if: failure() - run: docker compose logs + run: docker compose --env-file .env.${{ env.DOMAIN }} logs - name: Stop proxy if: always() run: | - docker compose down + docker compose --env-file .env.${{ env.DOMAIN }} down docker rm -f upstream || true diff --git a/.gitignore b/.gitignore index eb353ba..2a99c9d 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,10 @@ certs/ .DS_Store # env files -.env +.env* +!.env.example -# AI agents +# Editors .claude/ +.idea/ +.vscode/ diff --git a/README.md b/README.md index df58e9a..a437328 100644 --- a/README.md +++ b/README.md @@ -11,90 +11,74 @@ A Dockerized Caddy reverse proxy with automatic SSL certificate generation for l ## Quick Start -1. Configure your domain in `.env`: +1. Create an env file for your domain (e.g., `.env.local.example.com`): ``` DOMAIN=local.example.com UPSTREAM_URL=http://host.docker.internal:3000 + HTTP_PORT=8080 + HTTPS_PORT=8443 ``` -> [!WARNING] -> `UPSTREAM_URL` must include the scheme and port. + > [!WARNING] + > `UPSTREAM_URL` must include the scheme and port. -2. Add your domain to the hosts file: - - **macOS/Linux:** - Edit `/etc/hosts` +2. Add your domain to hosts file: ```bash + # macOS/Linux sudo sh -c 'echo "127.0.0.1 local.example.com" >> /etc/hosts' - ``` - **Windows (PowerShell as Administrator):** - Edit `C:\Windows\System32\drivers\etc\hosts` - - ```powershell + # Windows (PowerShell as Admin) Add-Content -Path C:\Windows\System32\drivers\etc\hosts -Value "127.0.0.1 local.example.com" ``` -3. Generate certificates (first time only): +3. Generate certificates: ```bash - docker compose --profile setup run --rm mkcert + docker compose --env-file .env.local.example.com --profile setup run --rm mkcert ``` -4. Install the CA certificate (one-time): - - Replace `local.example.com` with your configured domain. - - **macOS:** +4. Install CA certificate (one-time per domain): ```bash + # macOS sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain ./certs/local.example.com.rootCA.pem - ``` - - **Linux (Debian/Ubuntu):** - ```bash - sudo cp ./certs/local.example.com.rootCA.pem /usr/local/share/ca-certificates/local.example.com.crt - sudo update-ca-certificates - ``` - - **Linux (Fedora/RHEL):** - - ```bash - sudo cp ./certs/local.example.com.rootCA.pem /etc/pki/ca-trust/source/anchors/local.example.com.pem - sudo update-ca-trust - ``` + # Linux (Debian/Ubuntu) + sudo cp ./certs/local.example.com.rootCA.pem /usr/local/share/ca-certificates/local.example.com.crt && sudo update-ca-certificates - **Linux (Arch):** + # Linux (Fedora/RHEL) + sudo cp ./certs/local.example.com.rootCA.pem /etc/pki/ca-trust/source/anchors/local.example.com.pem && sudo update-ca-trust - ```bash + # Linux (Arch) sudo trust anchor ./certs/local.example.com.rootCA.pem - ``` - **Windows (PowerShell as Administrator):** - - ```powershell + # Windows (PowerShell as Admin) Import-Certificate -FilePath .\certs\local.example.com.rootCA.pem -CertStoreLocation Cert:\LocalMachine\Root ``` - If `.pem` import fails, convert to `.cer` first: - - ```powershell - openssl x509 -in .\certs\local.example.com.rootCA.pem -out .\certs\local.example.com.rootCA.cer - Import-Certificate -FilePath .\certs\local.example.com.rootCA.cer -CertStoreLocation Cert:\LocalMachine\Root - ``` - 5. Start the proxy: ```bash - docker compose up -d + docker compose --env-file .env.local.example.com up -d ``` 6. Visit: `https://local.example.com:8443` -Note (Linux): Requires Docker Engine 20.10+ for `host-gateway` support. +> [!NOTE] +> Linux requires Docker Engine 20.10+ for `host-gateway` support. + +## Running Multiple Domains + +Run multiple instances by creating separate env files with different ports: + +```bash +docker compose --env-file .env.local.example.com up -d +docker compose --env-file .env.local.another.com up -d +``` + +Each instance runs in its own project namespace based on the domain name. ## Configuration @@ -105,11 +89,6 @@ Note (Linux): Requires Docker Engine 20.10+ for `host-gateway` support. | `HTTPS_PORT` | `8443` | HTTPS port (proxy) | | `UPSTREAM_URL` | `http://host.docker.internal:3000` | URL for your local app | -## Ports - -- `HTTP_PORT` (default `8080`) - HTTP (redirects to HTTPS) -- `HTTPS_PORT` (default `8443`) - HTTPS - ## Layout ``` diff --git a/docker-compose.yml b/docker-compose.yml index 7717e56..b963d08 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,9 +1,11 @@ +name: ssl-proxy-${DOMAIN:-localhost} services: mkcert: build: context: . dockerfile: Dockerfile.mkcert - container_name: mkcert + container_name: mkcert-${DOMAIN:-localhost} + hostname: ${DOMAIN:-localhost} profiles: - setup environment: @@ -15,7 +17,7 @@ services: build: context: . dockerfile: Dockerfile.caddy - container_name: ssl-proxy + container_name: ssl-proxy-${DOMAIN:-localhost} ports: - "${HTTP_PORT:-8080}:80" - "${HTTPS_PORT:-8443}:443" diff --git a/scripts/mkcert/entrypoint.sh b/scripts/mkcert/entrypoint.sh index 464c0a7..2b89f44 100644 --- a/scripts/mkcert/entrypoint.sh +++ b/scripts/mkcert/entrypoint.sh @@ -7,19 +7,22 @@ KEY_FILE="/certs/${DOMAIN}.key.pem" CA_FILE="/certs/${DOMAIN}.rootCA.pem" if [ ! -f "$CERT_FILE" ]; then - echo "Generating SSL certificate for ${DOMAIN}..." + echo "" + echo "Generating SSL certificate for ${DOMAIN}... 🔐" + echo "" mkcert -install mkcert -cert-file "$CERT_FILE" \ -key-file "$KEY_FILE" \ "$DOMAIN" cp "$(mkcert -CAROOT)/rootCA.pem" "$CA_FILE" - echo "=== Certificate generated ===" + echo "" + echo "Certificate generated ✅" else - echo "Certificate already exists for ${DOMAIN}, skipping generation." + echo "Certificate already exists for ${DOMAIN}, skipping generation ⏭️" fi echo "" -echo "=== Install CA certificate ===" +echo "Install CA certificate 📋" echo "" echo "macOS:" echo " sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain ./certs/${DOMAIN}.rootCA.pem"