From 9d7cb0f3727e3aef668d639973beb7b9c734aaee Mon Sep 17 00:00:00 2001 From: Arunavo Ray Date: Mon, 7 Jul 2025 16:20:24 +0530 Subject: [PATCH] feat: add custom CA certificate support - Add support for custom CA certificates in Docker setup - Two mounting options: individual certs or system CA bundle - Automatic detection and configuration via NODE_EXTRA_CA_CERTS - Enhanced documentation with setup guide in certs/README.md - Added ca-certificates package to Alpine base image - Updated docker-compose with clear volume mount examples - Bump version to 2.21.0 --- .env.example | 7 ++ .gitignore | 6 ++ Dockerfile | 9 ++- README.md | 1 + certs/README.md | 149 ++++++++++++++++++++++++++++++++++++++++ docker-compose.dev.yml | 7 ++ docker-compose.yml | 7 ++ docker-entrypoint.sh | 47 +++++++++++++ docs/CA_CERTIFICATES.md | 1 + package.json | 2 +- 10 files changed, 232 insertions(+), 4 deletions(-) create mode 100644 certs/README.md create mode 120000 docs/CA_CERTIFICATES.md diff --git a/.env.example b/.env.example index c832b28..8805438 100644 --- a/.env.example +++ b/.env.example @@ -37,3 +37,10 @@ JWT_SECRET=change-this-to-a-secure-random-string-in-production # Users can configure cleanup settings through the web interface # CLEANUP_ENABLED=false # CLEANUP_RETENTION_DAYS=7 + +# Optional TLS/SSL Configuration +# Option 1: Mount custom CA certificates in ./certs directory as .crt files +# The container will automatically combine them into a CA bundle +# Option 2: Mount your system CA bundle at /etc/ssl/certs/ca-certificates.crt +# See docker-compose.yml for volume mount examples +# GITEA_SKIP_TLS_VERIFY=false # WARNING: Only use for testing, disables TLS verification diff --git a/.gitignore b/.gitignore index c562295..e644028 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,9 @@ data/gitea-mirror.db # jetbrains setting folder .idea/ + +# Custom CA certificates (exclude actual certs but keep README) +certs/*.crt +certs/*.pem +certs/*.cer +!certs/README.md diff --git a/Dockerfile b/Dockerfile index a58fc43..d3cefe2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ FROM oven/bun:1.2.18-alpine AS base WORKDIR /app -RUN apk add --no-cache libc6-compat python3 make g++ gcc wget sqlite openssl +RUN apk add --no-cache libc6-compat python3 make g++ gcc wget sqlite openssl ca-certificates # ---------------------------- FROM base AS deps @@ -37,11 +37,14 @@ ENV HOST=0.0.0.0 ENV PORT=4321 ENV DATABASE_URL=file:data/gitea-mirror.db -RUN chmod +x ./docker-entrypoint.sh && \ +# Create directories and setup permissions +RUN mkdir -p /app/certs && \ + chmod +x ./docker-entrypoint.sh && \ mkdir -p /app/data && \ addgroup --system --gid 1001 nodejs && \ adduser --system --uid 1001 gitea-mirror && \ - chown -R gitea-mirror:nodejs /app/data + chown -R gitea-mirror:nodejs /app/data && \ + chown -R gitea-mirror:nodejs /app/certs USER gitea-mirror diff --git a/README.md b/README.md index 5512858..694b7e5 100644 --- a/README.md +++ b/README.md @@ -147,6 +147,7 @@ GNU General Public License v3.0 - see [LICENSE](LICENSE) file for details. ## Support - 📖 [Documentation](https://github.com/RayLabsHQ/gitea-mirror/tree/main/docs) +- 🔐 [Custom CA Certificates](docs/CA_CERTIFICATES.md) - 🐛 [Report Issues](https://github.com/RayLabsHQ/gitea-mirror/issues) - 💬 [Discussions](https://github.com/RayLabsHQ/gitea-mirror/discussions) - 🔧 [Proxmox VE Script](https://community-scripts.github.io/ProxmoxVE/scripts?id=gitea-mirror) \ No newline at end of file diff --git a/certs/README.md b/certs/README.md new file mode 100644 index 0000000..dcf4243 --- /dev/null +++ b/certs/README.md @@ -0,0 +1,149 @@ +# Custom CA Certificate Support + +This guide explains how to configure Gitea Mirror to work with self-signed certificates or custom Certificate Authorities (CAs). + +> **📁 This is the certs directory!** Place your `.crt` certificate files directly in this directory and they will be automatically loaded when the Docker container starts. + +## Overview + +When connecting to a Gitea instance that uses self-signed certificates or certificates from a private CA, you need to configure the application to trust these certificates. Gitea Mirror supports mounting custom CA certificates that will be automatically configured for use. + +## Configuration Steps + +### 1. Prepare Your CA Certificates + +You're already in the right place! Simply copy your CA certificate(s) into this `certs` directory with `.crt` extension: + +```bash +# From the project root: +cp /path/to/your/ca-certificate.crt ./certs/ + +# Or if you're already in the certs directory: +cp /path/to/your/ca-certificate.crt . +``` + +You can add multiple CA certificates - they will all be combined into a single bundle. + +### 2. Mount Certificates in Docker + +Edit your `docker-compose.yml` file to mount the certificates. You have two options: + +**Option 1: Mount individual certificates from certs directory** +```yaml +services: + gitea-mirror: + # ... other configuration ... + volumes: + - gitea-mirror-data:/app/data + - ./certs:/app/certs:ro # Mount CA certificates directory +``` + +**Option 2: Mount system CA bundle (if your CA is already installed system-wide)** +```yaml +services: + gitea-mirror: + # ... other configuration ... + volumes: + - gitea-mirror-data:/app/data + - /etc/ssl/certs/ca-certificates.crt:/etc/ssl/certs/ca-certificates.crt:ro +``` + +> **Note**: Use Option 2 if you've already added your CA certificate to your system's certificate store using `update-ca-certificates` or similar commands. + +> **System CA Bundle Locations**: +> - Debian/Ubuntu: `/etc/ssl/certs/ca-certificates.crt` +> - RHEL/CentOS/Fedora: `/etc/pki/tls/certs/ca-bundle.crt` +> - Alpine Linux: `/etc/ssl/certs/ca-certificates.crt` +> - macOS: `/etc/ssl/cert.pem` + +### 3. Start the Container + +Start or restart your container: + +```bash +docker-compose up -d +``` + +The container will automatically: +1. Detect any `.crt` files in `/app/certs` (Option 1) OR detect mounted system CA bundle (Option 2) +2. For Option 1: Combine certificates into a CA bundle +3. Configure Node.js to use these certificates via `NODE_EXTRA_CA_CERTS` + +You should see log messages like: + +**For Option 1 (individual certificates):** +``` +Custom CA certificates found, configuring Node.js to use them... +Adding certificate: my-ca.crt +NODE_EXTRA_CA_CERTS set to: /app/certs/ca-bundle.crt +``` + +**For Option 2 (system CA bundle):** +``` +System CA bundle mounted, configuring Node.js to use it... +NODE_EXTRA_CA_CERTS set to: /etc/ssl/certs/ca-certificates.crt +``` + +## Testing & Troubleshooting + +### Disable TLS Verification (Testing Only) + +For testing purposes only, you can disable TLS verification entirely: + +```yaml +environment: + - GITEA_SKIP_TLS_VERIFY=true +``` + +**WARNING**: This is insecure and should never be used in production! + +### Common Issues + +1. **Certificate not recognized**: Ensure your certificate file has a `.crt` extension +2. **Connection still fails**: Check that the certificate is in PEM format +3. **Multiple certificates needed**: Add all required certificates (root and intermediate) to the certs directory + +### Verifying Certificate Loading + +Check the container logs to confirm certificates are loaded: + +```bash +docker-compose logs gitea-mirror | grep "CA certificates" +``` + +## Security Considerations + +- Always use proper CA certificates in production +- Never disable TLS verification in production environments +- Keep your CA certificates secure and limit access to the certs directory +- Regularly update certificates before they expire + +## Example Setup + +Here's a complete example for a self-hosted Gitea with custom CA: + +1. Copy your Gitea server's CA certificate to this directory: + ```bash + cp /etc/ssl/certs/my-company-ca.crt ./certs/ + ``` + +2. Update `docker-compose.yml`: + ```yaml + services: + gitea-mirror: + image: ghcr.io/raylabshq/gitea-mirror:latest + volumes: + - gitea-mirror-data:/app/data + - ./certs:/app/certs:ro + environment: + - GITEA_URL=https://gitea.mycompany.local + - GITEA_TOKEN=your-token + # ... other configuration ... + ``` + +3. Start the service: + ```bash + docker-compose up -d + ``` + +The application will now trust your custom CA when connecting to your Gitea instance. \ No newline at end of file diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 76713bd..a4824c9 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -54,6 +54,11 @@ services: - "4321:4321" volumes: - gitea-mirror-data:/app/data + # Mount custom CA certificates - choose one option: + # Option 1: Mount individual CA certificates from certs directory + # - ./certs:/app/certs:ro + # Option 2: Mount system CA bundle (if your CA is already in system store) + # - /etc/ssl/certs/ca-certificates.crt:/etc/ssl/certs/ca-certificates.crt:ro depends_on: - gitea environment: @@ -80,6 +85,8 @@ services: - GITEA_ORGANIZATION=${GITEA_ORGANIZATION:-github-mirrors} - GITEA_ORG_VISIBILITY=${GITEA_ORG_VISIBILITY:-public} - DELAY=${DELAY:-3600} + # Optional: Skip TLS verification (insecure, use only for testing) + # - GITEA_SKIP_TLS_VERIFY=${GITEA_SKIP_TLS_VERIFY:-false} healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:4321/api/health"] interval: 30s diff --git a/docker-compose.yml b/docker-compose.yml index c75cab5..527ca05 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -18,6 +18,11 @@ services: - "4321:4321" volumes: - gitea-mirror-data:/app/data + # Mount custom CA certificates - choose one option: + # Option 1: Mount individual CA certificates from certs directory + # - ./certs:/app/certs:ro + # Option 2: Mount system CA bundle (if your CA is already in system store) + # - /etc/ssl/certs/ca-certificates.crt:/etc/ssl/certs/ca-certificates.crt:ro environment: - NODE_ENV=production - DATABASE_URL=file:data/gitea-mirror.db @@ -42,6 +47,8 @@ services: - GITEA_ORGANIZATION=${GITEA_ORGANIZATION:-github-mirrors} - GITEA_ORG_VISIBILITY=${GITEA_ORG_VISIBILITY:-public} - DELAY=${DELAY:-3600} + # Optional: Skip TLS verification (insecure, use only for testing) + # - GITEA_SKIP_TLS_VERIFY=${GITEA_SKIP_TLS_VERIFY:-false} healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=3", "--spider", "http://localhost:4321/api/health"] interval: 30s diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index 1ee7560..2ea977d 100644 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -5,6 +5,53 @@ set -e # Ensure data directory exists mkdir -p /app/data +# Handle custom CA certificates +if [ -d "/app/certs" ] && [ "$(ls -A /app/certs/*.crt 2>/dev/null)" ]; then + echo "Custom CA certificates found, configuring Node.js to use them..." + + # Combine all CA certificates into a bundle for Node.js + CA_BUNDLE="/app/certs/ca-bundle.crt" + > "$CA_BUNDLE" + + for cert in /app/certs/*.crt; do + if [ -f "$cert" ]; then + echo "Adding certificate: $(basename "$cert")" + cat "$cert" >> "$CA_BUNDLE" + echo "" >> "$CA_BUNDLE" # Add newline between certificates + fi + done + + # Set Node.js to use the custom CA bundle + export NODE_EXTRA_CA_CERTS="$CA_BUNDLE" + echo "NODE_EXTRA_CA_CERTS set to: $NODE_EXTRA_CA_CERTS" + + # For Bun compatibility, also set the CA bundle in system location if writable + if [ -f "/etc/ssl/certs/ca-certificates.crt" ] && [ -w "/etc/ssl/certs/" ]; then + echo "Appending custom certificates to system CA bundle..." + cat "$CA_BUNDLE" >> /etc/ssl/certs/ca-certificates.crt + fi + +else + echo "No custom CA certificates found in /app/certs" +fi + +# Check if system CA bundle is mounted and use it +if [ -f "/etc/ssl/certs/ca-certificates.crt" ] && [ ! -L "/etc/ssl/certs/ca-certificates.crt" ]; then + # Check if it's a mounted file (not the default symlink) + if [ "$(stat -c '%d' /etc/ssl/certs/ca-certificates.crt 2>/dev/null)" != "$(stat -c '%d' / 2>/dev/null)" ] || \ + [ "$(stat -f '%d' /etc/ssl/certs/ca-certificates.crt 2>/dev/null)" != "$(stat -f '%d' / 2>/dev/null)" ]; then + echo "System CA bundle mounted, configuring Node.js to use it..." + export NODE_EXTRA_CA_CERTS="/etc/ssl/certs/ca-certificates.crt" + echo "NODE_EXTRA_CA_CERTS set to: $NODE_EXTRA_CA_CERTS" + fi +fi + +# Optional: If GITEA_SKIP_TLS_VERIFY is set, configure accordingly +if [ "$GITEA_SKIP_TLS_VERIFY" = "true" ]; then + echo "Warning: GITEA_SKIP_TLS_VERIFY is set to true. This is insecure!" + export NODE_TLS_REJECT_UNAUTHORIZED=0 +fi + # Generate a secure JWT secret if one isn't provided or is using the default value JWT_SECRET_FILE="/app/data/.jwt_secret" if [ "$JWT_SECRET" = "your-secret-key-change-this-in-production" ] || [ -z "$JWT_SECRET" ]; then diff --git a/docs/CA_CERTIFICATES.md b/docs/CA_CERTIFICATES.md new file mode 120000 index 0000000..07e66c1 --- /dev/null +++ b/docs/CA_CERTIFICATES.md @@ -0,0 +1 @@ +../certs/README.md \ No newline at end of file diff --git a/package.json b/package.json index 3d431eb..7f92bee 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "gitea-mirror", "type": "module", - "version": "2.20.1", + "version": "2.21.0", "engines": { "bun": ">=1.2.9" },