{"id":32692902,"url":"https://github.com/hnrobert/sslly-nginx","last_synced_at":"2026-05-16T10:03:53.773Z","repository":{"id":320485034,"uuid":"1074195219","full_name":"hnrobert/sslly-nginx","owner":"hnrobert","description":"A smart Nginx SSL reverse proxy manager that automatically configures SSL certificates and proxies traffic to your local applications.","archived":false,"fork":false,"pushed_at":"2026-05-15T08:23:58.000Z","size":923,"stargazers_count":2,"open_issues_count":2,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-15T10:38:29.447Z","etag":null,"topics":["automation","docker","nginx","ssl"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hnrobert.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-10-11T10:20:52.000Z","updated_at":"2026-05-14T15:36:15.000Z","dependencies_parsed_at":"2025-10-24T04:19:09.577Z","dependency_job_id":"5dae6cb4-59ec-4aad-a139-7b57100f9427","html_url":"https://github.com/hnrobert/sslly-nginx","commit_stats":null,"previous_names":["hnrobert/sslly-nginx"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/hnrobert/sslly-nginx","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hnrobert%2Fsslly-nginx","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hnrobert%2Fsslly-nginx/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hnrobert%2Fsslly-nginx/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hnrobert%2Fsslly-nginx/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hnrobert","download_url":"https://codeload.github.com/hnrobert/sslly-nginx/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hnrobert%2Fsslly-nginx/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33098340,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-16T04:41:52.686Z","status":"ssl_error","status_checked_at":"2026-05-16T04:41:52.009Z","response_time":115,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["automation","docker","nginx","ssl"],"created_at":"2025-11-01T16:02:07.774Z","updated_at":"2026-05-16T10:03:53.761Z","avatar_url":"https://github.com/hnrobert.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# sslly-nginx\n\nA smart Nginx SSL reverse proxy manager that automatically configures SSL certificates and proxies traffic to your local applications.\n\n\u003e I HATE writing Nginx config, that's why this project was born.  \n\u003e Just tell this tool the port and domain, and let it handle the rest.  \n\u003e \u003cp align=\"right\"\u003e\u003cstrong\u003eRobert He\u003c/strong\u003e\u003c/p\u003e\n\n![logo](assets/images/logo.png)\n\n## Features\n\n- **Simple Rules**: Just map port to domains in a YAML file, no more Nginx config writing\n- **Automatic Configuration**: Watches for configuration and SSL certificate change, automatically reloads Nginx\n- **SSL Management**: Automatically scans and maps SSL certificates to domains\n- **Hot Reload**: Updates Nginx configuration without downtime when files change\n- **Error Recovery**: Maintains the last working configuration and rolls back on failures\n- **Docker Ready**: Runs as a containerized service with Docker Compose\n- **FRP Friendly**: Easy integration with FRP for secure remote access to local services\n\n### Supported Features\n\n- [x] HTTP and HTTPS proxying\n- [x] Automatic HTTP → HTTPS redirection for domains with valid certificates\n- [x] TCP and UDP stream forwarding\n- [x] CORS configuration (optional)\n- [x] Custom log levels and formats (optional)\n- [x] WebSocket support\n- [x] Static site hosting\n\n## Quick Start\n\n### One-Command Setup\n\n```bash\n# Set up working directory\nexport SSLLY_NGINX_HOME=$HOME/sslly-nginx\nmkdir -p $SSLLY_NGINX_HOME \u0026\u0026 cd $SSLLY_NGINX_HOME\n\n# Download Docker Compose configuration\ncurl -fsSL https://raw.githubusercontent.com/hnrobert/sslly-nginx/main/docker-compose.yml -o docker-compose.yml\n\n# Start the service\ndocker-compose up -d\n```\n\nThe service will start with default configuration and create `configs/` and `ssl/` directories.\n\n### Customize Configuration\n\nEdit `configs/proxy.yaml` to add your routes:\n\n```bash\n# View logs\ndocker-compose logs -f\n\n# Stop service\ndocker-compose down\n```\n\n### Add SSL Certificates\n\nDrop certificate files into the `ssl/` directory:\n\n```text\nssl/\n├── example.com.crt\n├── example.com.key\n└── api.example.com_bundle.crt\n```\n\n## Documentation\n\n- [Configuration Reference](docs/CONFIG_REFERENCE.md) - Complete configuration format and rules\n- [CORS Configuration](docs/CORS.md) - Comprehensive CORS setup and best practices\n- [FRP Integration](docs/FRP.md) - Set up FRP for remote access to local services\n\n## Configuration\n\n### Configuration Format Summary\n\n```yaml\nupstream_key:\n  - listener_key_1\n  - listener_key_2\n```\n\n### upstream_key Format\n\n```md\n\u003cupstream_protocol\u003edomain:port/routes\n```\n\nor for static sites:\n\n```md\nstatic_route//additional/routes\n```\n\n| Component | Required | Default | Description |\n|-----------|----------|---------|-------------|\n| `upstream_protocol` | No | `http` | `https`, `tcp`, `udp` (omit for `http`) |\n| `domain` | No | `127.0.0.1` | IP or hostname (IPv6: `[::1]`) |\n| `port` | No | Protocol default | Port number |\n| `routes` | No | - | URL path routing |\n| `static_route` | - | - | Path representing www root location in filesystem starting with `/` or `.` or `..` (`.` = `/app`) |\n\n### listener_key Format\n\n```md\n\u003clisten_protocol\u003elistened_server_name|listened_port\n```\n\n| Component | Required | Default | Description |\n|-----------|----------|---------|-------------|\n| `listen_protocol` | No | Smart mode | `http`, `https`, `tcp`, `udp` |\n| `listened_server_name` | No | All interfaces | Server name (domain) |\n| `listened_port` | No | Env var ports | Listen port |\n\n### Quick Examples\n\n```yaml\n# HTTP proxy to localhost:8080\n8080:\n  - example.com\n\n# HTTPS upstream\n\u003chttps\u003eapi.secure.com:\n  - example.com\n\n# TCP forwarding\n\u003ctcp\u003e9122:\n  - 8122\n\n# Static site (relative path, . = /app)\n./static:\n  - static.example.com\n\n# Static site (parent path, .. = /)\n../data:\n  - data.example.com\n\n# Static with route path (using //)\n/app/static//docs:\n  - docs.example.com\n```\n\nFor complete format specification and advanced examples, see [Configuration Reference](docs/CONFIG_REFERENCE.md).\n\n### Optional Configuration Files\n\n#### CORS Configuration\n\nConfigure CORS (Cross-Origin Resource Sharing) settings globally or per-domain.\n\n```yaml\napi.example.com:\n  allow_origin: 'https://app.example.com'\n  allow_methods: [GET, POST, PUT, DELETE, OPTIONS]\n  allow_headers: [Content-Type, Authorization]\n  allow_credentials: true\n```\n\nFor more please check [CORS Configuration](docs/CORS.md) for comprehensive CORS setup guide and best practices examples.\n\n### SSL Certificate Structure\n\nPlace SSL certificates in the `ssl/` directory. The application automatically matches certificate files (`.crt`) with their corresponding private key files (`.key`) based on the domain information contained within the SSL certificates themselves.\n\n```bash\nssl/\n├── production/\n│   ├── example.com_bundle.crt\n│   └── example.com_bundle.key\n├── staging/\n│   ├── staging.example.com.crt\n│   └── staging.example.com.key\n└── api.example.com.crt\n    └── api.example.com.key\n```\n\n**Important Notes**:\n\n- Duplicate certificates are allowed for each domain, If multiple pairs of certificate+key are found, the farthest expiration time is selected.\n- Certificate and key files are optional (a domain without a matched cert/key will be served over HTTP)\n- **SSL certificates are optional**: If no certificate is found for a domain, the service will proxy HTTP traffic directly to your applications\n- **HTTPS to HTTP redirect**: If HTTPS is accessed for domains without valid certificates, traffic is redirected to HTTP (301)\n\n### Backup \u0026 Crash Recovery\n\nTo make hot-reloads safer, `sslly-nginx` keeps a persistent on-disk snapshot of the last known-good configuration.\n\n- Backup folder: `configs/.sslly-backups/`\n- Snapshot content: `configs/` + `ssl/` + generated `/etc/nginx/nginx.conf`\n- Runtime cache: The currently used cert/key files are copied into `configs/.sslly-runtime/current/` and nginx.conf only references that cache, so edits under `ssl/` won't affect the running nginx process until a successful reload.\n\nCrash detection: If the previous run died mid-reload, the next start detects the unfinished reload and automatically restores the last known-good snapshot.\n\n### HTTP-Only Mode\n\nIf you don't have SSL certificates yet but want to serve some domains over HTTP only:\n\n1. The application will automatically detect missing certificates\n2. Domains without certificates will be served over HTTP (no redirect)\n3. Domains with certificates will use HTTPS with automatic HTTP → HTTPS redirect\n4. **HTTPS fallback**: If someone accesses HTTPS for a domain without a valid certificate, they'll be redirected to HTTP with a 301 status\n5. You can mix HTTP and HTTPS domains in the same configuration\n\nExample scenario:\n\n```yaml\n# proxy.yaml\n1234:\n  - secure.example.com # Has certificate → HTTPS\n  - dev.example.com # No certificate → HTTP only\n```\n\n## Features in Detail\n\n### Automatic HTTPS Redirect\n\nWhen SSL certificates are detected:\n\n- All HTTP traffic for domains **with certificates** is automatically redirected to HTTPS\n- HTTPS traffic for domains **without certificates** is redirected to HTTP (301) to avoid certificate errors\n- If no certificates are found for any domain, HTTP traffic is proxied directly to your applications\n\n### Hot Reload\n\nThe application watches for changes in:\n\n- Configuration files (`./configs/proxy.yaml`, optional `./configs/cors.yaml`, `./configs/logs.yaml`)\n- SSL certificates (`./ssl/**/*`)\n\nNote: internal state folders under `configs/` (like `configs/.sslly-backups/` and `configs/.sslly-runtime/`) are ignored by the watcher to avoid feedback loops.\n\nWhen changes are detected:\n\n1. New configuration is generated\n2. Nginx configuration is tested\n3. If valid, Nginx is reloaded\n4. If invalid, the previous working configuration is restored (including on-disk `configs/` + `ssl/` contents)\n\n### Logs: Domain Summary\n\nOn startup and after every successful reload, the service prints a single domain summary instead of logging domain status one-by-one:\n\n- `Matched:` (INFO) domains with a valid certificate+key pair (labeled \"SSL\")\n- `No-cert:` (WARN) domains with no matched certificate+key (served over HTTP)\n- `Expired:` (WARN) domains with a matched certificate+key but the certificate is expired\n- `Multi-certs:` (WARN) domains where multiple certificate candidates were found; the selected cert path is shown along with the ignored count.\n\n### Error Handling\n\n- **Initial Startup**:\n  - If configuration is invalid, the service stops\n  - Missing SSL certificates are **not** an error - service runs in HTTP-only mode\n- **Runtime Errors**: If reload fails, the application:\n  - Logs detailed error messages\n  - Restores the last working configuration\n  - Continues running with previous settings\n\n## Testing\n\nRun unit tests:\n\n```bash\ngo test ./...\n```\n\nRun tests with coverage:\n\n```bash\ngo test ./... -coverprofile=coverage.out\ngo tool cover -func=coverage.out\ngo tool cover -html=coverage.out -o coverage.html\n```\n\n### WebSocket Support\n\nThe generated Nginx configuration includes WebSocket support for all proxied applications.\n\n### Advanced Proxy Features\n\nThe reverse proxy includes optimized settings for various applications:\n\n- **Large File Upload**: Supports files up to 100MB by default\n- **Correct Host Header**: Uses `$host` to preserve the original request hostname (critical for apps like qBittorrent, OnlineJudge)\n- **Proxy Headers**: Includes all standard headers:\n  - `Host`: Original request hostname (e.g., `torrent.hnrobert.space`)\n  - `X-Real-IP`: Client's real IP address\n  - `X-Forwarded-For`: Full proxy chain\n  - `X-Forwarded-Host`: Original Host header\n  - `X-Forwarded-Proto`: Original protocol (http/https)\n- **Cookie Security**: Automatically sets Secure flag for cookies when using HTTPS\n- **Timeouts**: Configured with 60s timeouts for connect/send/read operations\n- **Proxy Buffering**: Optimized buffer settings for better performance\n\nThese settings work well with applications like:\n\n- qBittorrent (WebUI)\n- Portainer (Docker management)\n- Jellyfin (Media streaming)\n- Home Assistant (Smart home)\n- OnlineJudge (Competitive programming)\n- And most other web applications\n\n## FRP Integration\n\n`sslly-nginx` integrates seamlessly with [FRP (Fast Reverse Proxy)](https://github.com/fatedier/frp) to expose your local services through remote servers, enabling secure remote access to your applications from anywhere.\n\n### Key Benefits\n\n- **Secure Remote Access**: Access your local applications from anywhere via HTTPS\n- **Custom Domains**: Use your own domain names instead of IP addresses\n- **SSL Management**: SSL certificates configured locally for domain-based routing\n- **Flexible Port Configuration**: Change HTTP/HTTPS ports to avoid conflicts with FRP\n\n### Quick Setup\n\n1. **Configure Ports**: Modify `docker-compose.yml` to use non-standard ports:\n\n   ```yaml\n   environment:\n     - SSLLY_DEFAULT_HTTP_LISTEN_PORT=9980 # HTTP traffic\n     - SSLLY_DEFAULT_HTTPS_LISTEN_PORT=9943 # HTTPS traffic\n   ```\n\n   \u003e **Note:** The legacy environment variables `SSL_NGINX_HTTP_PORT` and `SSL_NGINX_HTTPS_PORT` are also supported for backward compatibility.\n\n2. **Setup FRP Client**: Create `frpc.toml`:\n\n   ```toml\n   serverAddr = \"your-frp-server.com\"\n   serverPort = 7000\n   auth.method = \"token\"\n   auth.token = \"your-secure-token\"\n\n   # HTTPS proxy - handles SSL/TLS traffic\n   [[proxies]]\n   name = \"sslly-nginx-https\"\n   type = \"https\"\n   localIP = \"127.0.0.1\"\n   localPort = 9943\n   customDomains = [\"*.yourdomain.com\", \"yourdomain.com\"]\n\n   # HTTP proxy - handles plain HTTP and auto-redirects\n   [[proxies]]\n   name = \"sslly-nginx-http\"\n   type = \"http\"\n   localIP = \"127.0.0.1\"\n   localPort = 9980\n   customDomains = [\"*.yourdomain.com\", \"yourdomain.com\"]\n   ```\n\n3. **Start Services**: Run both FRP client and sslly-nginx\n\nFor detailed FRP integration guide, see [docs/FRP.md](docs/FRP.md).\n\n## Development\n\n### Build Locally\n\n```bash\n# Build the binary\nmake build\n\n# Run tests\nmake test\n\n# Run tests with coverage\nmake test-coverage\n\n# Format code\nmake fmt\n\n# Run linter\nmake lint\n```\n\n### Build Docker Image\n\n```bash\n# Build image\nmake docker-build\n\n# Or use Docker directly\ndocker build -t sslly-nginx:latest .\n```\n\n### Run Locally (without Docker)\n\n```bash\n# Note: Requires Nginx installed on your system\nmake run\n```\n\n## CI/CD Workflows\n\nThe project includes three GitHub Actions workflows:\n\n### 1. CI Workflow (`ci.yml`)\n\n- **Triggers**: All branch pushes and pull requests\n- **Actions**:\n  - Build the application\n  - Run tests\n  - Run linter and format checks\n- **No Docker image is built**\n\n### 2. Docker Build Workflow (`docker-build.yml`)\n\n- **Triggers**: Pushes to `main` and `develop` branches\n- **Actions**:\n  - Run tests\n  - Build Docker image\n  - Push to `ghcr.io`\n- **Tags**:\n  - `main` branch → `latest` tag\n  - `develop` branch → `develop` tag\n\n### 3. Release Workflow (`release.yml`)\n\n- **Triggers**:\n  - Git tag push (e.g., `v1.0.0`)\n  - Manual workflow dispatch\n- **Actions**:\n  - Create tag (if workflow_dispatch)\n  - Run tests\n  - Build and push Docker image with version tag\n  - Create GitHub release\n\n## Docker Compose Configuration\n\nThe `docker-compose.yml` is configured with:\n\n- **Network Mode**: `host` - Uses host networking for direct port access\n- **Restart Policy**: `on-failure` - Stops on errors, auto-starts on system boot\n- **Volumes**:\n  - `./configs:/app/configs:ro` - Configuration (read-only)\n  - `./ssl:/app/ssl:ro` - SSL certificates (read-only)\n\n### Environment Variables\n\n- `SSLLY_DEFAULT_HTTP_LISTEN_PORT` (default: `80`) — port Nginx listens for HTTP and redirect to HTTPS\n- `SSLLY_DEFAULT_HTTPS_LISTEN_PORT` (default: `443`) — port Nginx listens for HTTPS\n\n\u003e **Note:** The legacy environment variables `SSL_NGINX_HTTP_PORT` and `SSL_NGINX_HTTPS_PORT` are still supported for backward compatibility but are deprecated.\n\n### Viewing Logs\n\nAll logs (application + nginx access/error logs) are forwarded to Docker's log collector:\n\n```bash\n# View all logs\ndocker-compose logs -f\n\n# View only application logs\ndocker-compose logs -f sslly-nginx\n\n# View last 100 lines\ndocker-compose logs --tail=100 sslly-nginx\n```\n\nNginx access and error logs are automatically forwarded to stdout/stderr and visible via `docker logs`\n\n## Project Structure\n\n```bash\nsslly-nginx/\n├── cmd/\n│   └── sslly-nginx/\n│       └── main.go              # Application entry point\n├── internal/\n│   ├── app/\n│   │   └── app.go               # Application logic\n│   ├── config/\n│   │   ├── config.go            # Configuration loader\n│   │   └── config_test.go\n│   ├── nginx/\n│   │   └── nginx.go             # Nginx management\n│   ├── ssl/\n│   │   ├── ssl.go               # Certificate scanner\n│   │   └── ssl_test.go\n│   └── watcher/\n│       └── watcher.go           # File system watcher\n├── .github/\n│   └── workflows/\n│       ├── ci.yml               # CI pipeline\n│       ├── docker-build.yml     # Docker build pipeline\n│       └── release.yml          # Release pipeline\n├── configs/\n│   ├── proxy.yaml               # Proxy mappings (required)\n│   ├── cors.yaml                # Optional CORS settings\n│   ├── logs.yaml                # Optional log settings\n│   ├── proxy.example.yaml       # Example proxy mappings\n│   ├── cors.example.yaml        # Example CORS settings\n│   └── logs.example.yaml        # Example log settings\n├── ssl/\n│   └── README.md                # SSL certificate guide\n├── Dockerfile                   # Docker image definition\n├── docker-compose.yml           # Docker Compose configuration\n├── Makefile                     # Build automation\n├── go.mod                       # Go module definition\n└── README.md                    # This file\n```\n\n## Logging\n\nThe application logs important events:\n\n- Configuration changes detected\n- Certificate scanning results\n- Nginx reload success/failure\n- Error details with recovery actions\n\nLogs can be viewed with:\n\n```bash\ndocker-compose logs -f\n```\n\n## Troubleshooting\n\n### Container Stops Immediately\n\n**Cause**: Invalid configuration or missing certificates\n\n**Solution**:\n\n1. Check logs: `docker-compose logs`\n2. Verify `configs/proxy.yaml` exists and is valid YAML\n3. Ensure all domains have matching certificates in `ssl/`\n\n### Certificate Not Found\n\n**Cause**: Certificate file naming doesn't match expected patterns\n\n**Solution**:\n\n1. Check certificate files follow naming pattern: `domain.crt/key` or `domain_bundle.crt/key`\n2. Ensure both `.crt` and `.key` files exist\n3. Check logs for certificate scanning results\n\n### Nginx Fails to Reload\n\n**Cause**: Configuration error or certificate issues\n\n**Solution**:\n\n1. Application automatically rolls back to last working configuration\n2. Check logs for specific error messages\n3. Fix the configuration or certificate issue\n4. Changes will be automatically detected and reloaded\n\n## Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request.\n\n## License\n\nSee [LICENSE](LICENSE) file for details.\n\n## Support\n\nFor issues and questions, please use the [GitHub Issues](https://github.com/hnrobert/sslly-nginx/issues) page.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhnrobert%2Fsslly-nginx","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhnrobert%2Fsslly-nginx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhnrobert%2Fsslly-nginx/lists"}