Skip to content
Back to skills

Local Ssl

BSecurity

Enable HTTPS for local development with trusted SSL certificates. Use when developers need to test SSL/TLS features, work with third-party APIs requiring HTTPS, or simulate production environments. Supports mkcert, OpenSSL, and automatic certificate trust configuration for macOS, Linux, and Windows.

  • 666 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added February 9, 2026
developmenttypescriptrustbashreactnodeexpressdockertestinggitapi

Works with

  • api

Security analysis

B76/100
  • mediumUses curl or wget to download content
  • highPerforms destructive filesystem operations
  • criticalExfiltrates credentials via HTTP β€” exact pattern from Snyk ToxicSkills study

Pro shows the line behind each finding and how to fix it

Scanned February 12, 2026

npx -y skills add majiayu000/claude-skill-registry --skill local-ssl --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Local Ssl?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Local Ssl
[![Security: B β€” Skills Directory](https://www.skillsdirectory.com/api/skills/majiayu000-local-ssl/badge)](https://www.skillsdirectory.com/skills/majiayu000-local-ssl)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: local-ssl
description: Enable HTTPS for local development with trusted SSL certificates. Use when developers need to test SSL/TLS features, work with third-party APIs requiring HTTPS, or simulate production environments. Supports mkcert, OpenSSL, and automatic certificate trust configuration for macOS, Linux, and Windows.
---

# Local SSL/HTTPS

Enable HTTPS for local development environments with automatically trusted SSL certificates. This skill handles certificate generation, trust configuration, and web server setup.

## Core Workflows

### 1. mkcert Setup (Recommended Approach)

mkcert is the simplest way to generate locally-trusted certificates.

```bash
# Generate: scripts/setup-ssl.sh

#!/bin/bash
set -e

RED='\033[0;31m'
GREEN='\033[0;32m'
BLUE='\033[0;34m'
NC='\033[0m'

echo -e "${BLUE}πŸ” Setting up local SSL certificates...${NC}\n"

# Check if mkcert is installed
if ! command -v mkcert &> /dev/null; then
  echo -e "${BLUE}πŸ“¦ Installing mkcert...${NC}"
  
  # Detect OS and install mkcert
  if [[ "$OSTYPE" == "darwin"* ]]; then
    # macOS
    brew install mkcert nss  # nss for Firefox support
  elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
    # Linux
    if command -v apt-get &> /dev/null; then
      sudo apt-get install -y libnss3-tools
      curl -JLO "https://dl.filippo.io/mkcert/latest?for=linux/amd64"
      chmod +x mkcert-v*-linux-amd64
      sudo mv mkcert-v*-linux-amd64 /usr/local/bin/mkcert
    fi
  else
    echo -e "${RED}❌ Unsupported OS. Please install mkcert manually.${NC}"
    exit 1
  fi
fi

# Create certs directory
mkdir -p certs

# Install local CA
echo -e "${BLUE}πŸ”’ Installing local Certificate Authority...${NC}"
mkcert -install

# Generate certificates for localhost and custom domains
echo -e "${BLUE}πŸ”‘ Generating certificates...${NC}"
mkcert -cert-file certs/localhost.crt \
       -key-file certs/localhost.key \
       localhost 127.0.0.1 ::1 \
       *.localhost \
       local.dev \
       *.local.dev

echo -e "\n${GREEN}βœ… SSL certificates generated!${NC}"
echo -e "${BLUE}πŸ“ Certificate files:${NC}"
echo -e "   certs/localhost.crt"
echo -e "   certs/localhost.key"
```

### 2. Docker Compose with SSL

```yaml
# Update docker-compose.yml to mount certificates

version: '3.8'

services:
  frontend:
    build:
      context: ./frontend
      dockerfile: Dockerfile.dev
    ports:
      - "3000:3000"
      - "3443:3443"  # HTTPS port
    environment:
      - HTTPS=true
      - SSL_CRT_FILE=/certs/localhost.crt
      - SSL_KEY_FILE=/certs/localhost.key
    volumes:
      - ./frontend:/app
      - /app/node_modules
      - ./certs:/certs:ro  # Mount certificates as read-only
    networks:
      - app-network

  api:
    build:
      context: ./backend
      dockerfile: Dockerfile.dev
    ports:
      - "8000:8000"
      - "8443:8443"  # HTTPS port
    environment:
      - SSL_CERT=/certs/localhost.crt
      - SSL_KEY=/certs/localhost.key
    volumes:
      - ./backend:/app
      - /app/node_modules
      - ./certs:/certs:ro
    networks:
      - app-network

  nginx:
    image: nginx:alpine
    ports:
      - "443:443"
    volumes:
      - ./nginx/nginx-ssl.conf:/etc/nginx/conf.d/default.conf:ro
      - ./certs:/etc/nginx/certs:ro
    depends_on:
      - frontend
      - api
    networks:
      - app-network
```

### 3. Nginx SSL Configuration

```nginx
# Generate: nginx/nginx-ssl.conf

# Frontend HTTPS
server {
    listen 443 ssl http2;
    server_name localhost local.dev;

    ssl_certificate /etc/nginx/certs/localhost.crt;
    ssl_certificate_key /etc/nginx/certs/localhost.key;

    # SSL Configuration
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

    # Security headers
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;

    location / {
        proxy_pass http://frontend:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
        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 $scheme;
    }
}

# API HTTPS
server {
    listen 443 ssl http2;
    server_name api.localhost api.local.dev;

    ssl_certificate /etc/nginx/certs/localhost.crt;
    ssl_certificate_key /etc/nginx/certs/localhost.key;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

    location / {
        proxy_pass http://api:8000;
        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 $scheme;
    }
}

# HTTP to HTTPS redirect
server {
    listen 80;
    server_name localhost local.dev api.localhost api.local.dev;
    return 301 https://$host$request_uri;
}
```

### 4. Vite HTTPS Configuration

```typescript
// Generate: frontend/vite.config.ts (with HTTPS)

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import fs from 'fs';
import path from 'path';

export default defineConfig({
  plugins: [react()],
  server: {
    host: '0.0.0.0',
    port: 3000,
    https: process.env.HTTPS === 'true' ? {
      key: fs.readFileSync(path.resolve(__dirname, '../certs/localhost.key')),
      cert: fs.readFileSync(path.resolve(__dirname, '../certs/localhost.crt')),
    } : undefined,
    watch: {
      usePolling: true,
    },
  },
});
```

### 5. Node.js/Express HTTPS Setup

```typescript
// Generate: backend/src/server.ts (with HTTPS)

import express from 'express';
import https from 'https';
import http from 'http';
import fs from 'fs';
import path from 'path';

const app = express();

// Your middleware and routes here
app.use(express.json());

// Health check
app.get('/health', (req, res) => {
  res.json({ status: 'ok', protocol: req.protocol });
});

const PORT = process.env.PORT || 8000;
const HTTPS_PORT = 8443;

// Start HTTP server
http.createServer(app).listen(PORT, () => {
  console.log(`HTTP server running on http://localhost:${PORT}`);
});

// Start HTTPS server if certificates exist
if (process.env.SSL_CERT && process.env.SSL_KEY) {
  try {
    const httpsOptions = {
      key: fs.readFileSync(process.env.SSL_KEY),
      cert: fs.readFileSync(process.env.SSL_CERT),
    };

    https.createServer(httpsOptions, app).listen(HTTPS_PORT, () => {
      console.log(`HTTPS server running on https://localhost:${HTTPS_PORT}`);
    });
  } catch (error) {
    console.error('Failed to start HTTPS server:', error);
  }
}
```

### 6. OpenSSL Alternative (Manual)

For systems where mkcert isn't available:

```bash
# Generate: scripts/generate-certs-openssl.sh

#!/bin/bash
set -e

mkdir -p certs

# Generate private key
openssl genrsa -out certs/localhost.key 2048

# Generate certificate signing request
openssl req -new -key certs/localhost.key -out certs/localhost.csr \
  -subj "/C=US/ST=State/L=City/O=Development/CN=localhost"

# Generate self-signed certificate
openssl x509 -req -days 365 -in certs/localhost.csr \
  -signkey certs/localhost.key -out certs/localhost.crt \
  -extfile <(printf "subjectAltName=DNS:localhost,DNS:*.localhost,IP:127.0.0.1")

# Clean up CSR
rm certs/localhost.csr

echo "βœ… Certificates generated!"
echo "⚠️  You'll need to manually trust the certificate in your browser"
```

### 7. Certificate Trust Scripts

```bash
# Generate: scripts/trust-cert.sh

#!/bin/bash

RED='\033[0;31m'
GREEN='\033[0;32m'
BLUE='\033[0;34m'
NC='\033[0m'

CERT_FILE="certs/localhost.crt"

if [ ! -f "$CERT_FILE" ]; then
  echo -e "${RED}❌ Certificate not found: $CERT_FILE${NC}"
  exit 1
fi

echo -e "${BLUE}πŸ”’ Adding certificate to system trust store...${NC}"

if [[ "$OSTYPE" == "darwin"* ]]; then
  # macOS
  sudo security add-trusted-cert -d -r trustRoot \
    -k /Library/Keychains/System.keychain "$CERT_FILE"
  echo -e "${GREEN}βœ… Certificate trusted on macOS${NC}"
  
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
  # Linux
  sudo cp "$CERT_FILE" /usr/local/share/ca-certificates/localhost.crt
  sudo update-ca-certificates
  echo -e "${GREEN}βœ… Certificate trusted on Linux${NC}"
  
else
  echo -e "${RED}❌ Unsupported OS for automatic trust${NC}"
  echo "Please manually trust the certificate:"
  echo "  - Chrome: chrome://settings/certificates"
  echo "  - Firefox: about:preferences#privacy"
fi
```

## Environment Configuration

```bash
# Add to .env

# SSL Configuration
HTTPS=true
SSL_CERT_FILE=./certs/localhost.crt
SSL_KEY_FILE=./certs/localhost.key

# Update URLs to use HTTPS
VITE_API_URL=https://localhost:8443
API_BASE_URL=https://localhost:8443
```

## Testing SSL Setup

```bash
# Generate: scripts/test-ssl.sh

#!/bin/bash

echo "πŸ§ͺ Testing SSL setup..."

# Test HTTPS endpoint
if curl -k -s https://localhost:3443 > /dev/null 2>&1; then
  echo "βœ… Frontend HTTPS is working"
else
  echo "❌ Frontend HTTPS failed"
fi

if curl -k -s https://localhost:8443/health > /dev/null 2>&1; then
  echo "βœ… API HTTPS is working"
else
  echo "❌ API HTTPS failed"
fi

# Check certificate validity
echo ""
echo "πŸ“‹ Certificate details:"
openssl x509 -in certs/localhost.crt -noout -subject -dates
```

## Makefile Integration

```makefile
.PHONY: ssl-setup ssl-test ssl-clean

ssl-setup: ## Generate and trust SSL certificates
	@./scripts/setup-ssl.sh

ssl-test: ## Test SSL configuration
	@./scripts/test-ssl.sh

ssl-clean: ## Remove SSL certificates
	@rm -rf certs
	@echo "βœ… SSL certificates removed"
```

## Best Practices

1. **Never commit certificates** - Add `certs/` to .gitignore
2. **Use mkcert for development** - Easiest and most reliable
3. **Automate setup** - Include in onboarding scripts
4. **Test in all browsers** - Chrome, Firefox, Safari, Edge
5. **Document the process** - Help teammates get started quickly
6. **Use consistent domains** - *.localhost or *.local.dev

## Integration with zero-to-running

When both skills are active:
1. SSL is set up automatically during `make dev`
2. Services available over HTTPS
3. Certificates automatically trusted
4. Environment variables configured correctly

## Troubleshooting

**Certificate not trusted:**
```bash
# Reinstall CA
mkcert -uninstall
mkcert -install
```

**Port conflicts:**
```bash
# Change ports in .env
HTTPS_PORT=4443
```

**Browser shows NET::ERR_CERT_AUTHORITY_INVALID:**
- Run `mkcert -install` again
- Restart browser completely
- Check system keychain for certificate

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.