{"id":46490288,"url":"https://github.com/slauger/netscaler-certbot-hook","last_synced_at":"2026-03-06T10:30:53.532Z","repository":{"id":46764283,"uuid":"241105191","full_name":"slauger/netscaler-certbot-hook","owner":"slauger","description":"Automatic installation and renewal of ssl certificates on Citrix NetScaler ADCs","archived":false,"fork":false,"pushed_at":"2025-11-25T21:00:15.000Z","size":1901,"stargazers_count":10,"open_issues_count":0,"forks_count":5,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-11-29T01:49:05.515Z","etag":null,"topics":["adc","certbot","citrix","hook","letsencrypt","netscaler"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/netscaler-certbot-hook/","language":"Python","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/slauger.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":".github/CONTRIBUTING.md","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":"2020-02-17T12:43:27.000Z","updated_at":"2025-11-25T21:00:18.000Z","dependencies_parsed_at":"2022-09-06T02:10:22.701Z","dependency_job_id":null,"html_url":"https://github.com/slauger/netscaler-certbot-hook","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/slauger/netscaler-certbot-hook","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slauger%2Fnetscaler-certbot-hook","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slauger%2Fnetscaler-certbot-hook/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slauger%2Fnetscaler-certbot-hook/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slauger%2Fnetscaler-certbot-hook/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/slauger","download_url":"https://codeload.github.com/slauger/netscaler-certbot-hook/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slauger%2Fnetscaler-certbot-hook/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30171869,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-06T07:56:45.623Z","status":"ssl_error","status_checked_at":"2026-03-06T07:55:55.621Z","response_time":250,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6: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":["adc","certbot","citrix","hook","letsencrypt","netscaler"],"created_at":"2026-03-06T10:30:52.788Z","updated_at":"2026-03-06T10:30:53.429Z","avatar_url":"https://github.com/slauger.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# NetScaler Certbot Hook\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Python 3.8+](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/downloads/)\n\nAutomated SSL certificate management for Citrix NetScaler ADC. This tool seamlessly integrates with Certbot to install and renew Let's Encrypt certificates on NetScaler appliances via the NITRO API.\n\nPerfect for automating certificate lifecycle management in combination with DNS-01 challenges for fully automated, hands-free certificate renewals.\n\n## Features\n\n- ✅ **Automated Certificate Installation** - Upload and install certificates with a single command\n- ✅ **Smart Updates** - Only updates certificates when serial numbers differ\n- ✅ **Chain Certificate Handling** - Automatic linking to intermediate certificates\n- ✅ **Configuration Persistence** - Automatically saves NetScaler configuration\n- ✅ **Idempotent Operations** - Safe to run repeatedly, only changes when needed\n- ✅ **Custom Certificate Paths** - Supports non-standard certificate locations\n- ✅ **Comprehensive Validation** - Pre-flight checks for files, credentials, and configuration\n- ✅ **Detailed Error Messages** - Clear feedback when something goes wrong\n- ✅ **Type-Safe** - Full type hints for IDE support and static analysis\n\n## Architecture\n\n![Architecture](https://raw.githubusercontent.com/slauger/netscaler-certbot-hook/master/architecture.jpg)\n\nThe script connects to your NetScaler via NITRO API, compares certificate serial numbers, and performs uploads/installations only when necessary. Chain certificates are handled separately for security reasons.\n\n## Prerequisites\n\n- **Python** 3.8 or higher\n- **Citrix NetScaler ADC** with NITRO API access\n- **Certbot** (for Let's Encrypt certificate enrollment)\n- **Network access** to NetScaler management interface\n\n## Installation\n\n### Option 1: From PyPI (Recommended)\n\n```bash\n# Install directly from PyPI\npip install netscaler-certbot-hook\n```\n\nAfter installation, the `netscaler-certbot-hook` command will be available system-wide.\n\n### Option 2: From Source\n\n```bash\n# Clone the repository\ngit clone https://github.com/slauger/netscaler-certbot-hook.git\ncd netscaler-certbot-hook\n\n# Install in development mode\npip install -e .\n```\n\n### Option 3: Install dependencies only\n\n```bash\n# For manual script execution\npip install -r requirements.txt\n```\n\n### Dependencies\n\n- `pyOpenSSL\u003e=20.0.0` - SSL certificate handling\n- `requests\u003e=2.25.0` - NITRO API communication\n\n## Configuration\n\n### Environment Variables\n\nThe script requires the following environment variables:\n\n| Variable | Required | Default | Description |\n|----------|----------|---------|-------------|\n| `NS_URL` | Yes | - | NetScaler management URL (e.g., `https://192.168.10.10`) |\n| `NS_LOGIN` | No | `nsroot` | NetScaler administrator username |\n| `NS_PASSWORD` | No | `nsroot` | NetScaler administrator password |\n| `NS_VERIFY_SSL` | No | `true` | Verify SSL certificate (`true`, `false`, `1`, `0`) |\n\n**Example:**\n```bash\nexport NS_URL=https://192.168.10.10\nexport NS_LOGIN=nsroot\nexport NS_PASSWORD=your-secure-password\nexport NS_VERIFY_SSL=true\n```\n\n### Command-Line Arguments\n\n```bash\nnetscaler-certbot-hook --help\n```\n\n**Note:** If installed from PyPI, use `netscaler-certbot-hook`. If running from source, use `netscaler-certbot-hook` or `python3 -m netscaler_certbot_hook`.\n\n| Argument | Required | Default | Description |\n|----------|----------|---------|-------------|\n| `--name` | Yes | - | Certificate object name on NetScaler |\n| `--chain` | No | Auto-detected from CN | Chain certificate object name (auto-detected from certificate CN if not specified) |\n| `--cert` | No | `/etc/letsencrypt/live/\u003cname\u003e/cert.pem` | Path to certificate file |\n| `--privkey` | No | `/etc/letsencrypt/live/\u003cname\u003e/privkey.pem` | Path to private key file |\n| `--chain-cert` | No | `/etc/letsencrypt/live/\u003cname\u003e/chain.pem` | Path to chain certificate file |\n| `--verbose` | No | `false` | Enable verbose output (DEBUG level) |\n| `--quiet` | No | `false` | Suppress all output except errors |\n| `--update-chain` | No | `false` | Allow updating chain certificate if serial differs |\n| `--no-domain-check` | No | `false` | Skip domain validation when updating certificates |\n\n## Usage\n\n### Step 1: Enroll Certificate with Certbot\n\nFirst, obtain a certificate from Let's Encrypt using Certbot with DNS-01 challenge:\n\n#### Example with Cloudflare DNS:\n\n```bash\ncertbot --text --agree-tos --non-interactive certonly \\\n  --cert-name 'example.com' \\\n  -d 'example.com' \\\n  -d 'www.example.com' \\\n  -a dns-cloudflare \\\n  --dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \\\n  --keep-until-expiring\n```\n\n#### Example with other DNS providers:\n\n```bash\n# Route53 (AWS)\ncertbot certonly --dns-route53 -d example.com\n\n# Google Cloud DNS\ncertbot certonly --dns-google -d example.com\n\n# Manual DNS (for testing)\ncertbot certonly --manual --preferred-challenges dns -d example.com\n```\n\n### Step 2: Install Certificate on NetScaler\n\n#### Basic Usage (Default Paths):\n\n```bash\nnetscaler-certbot-hook --name example.com\n```\n\n#### Custom Certificate Paths:\n\n```bash\nnetscaler-certbot-hook --name example.com \\\n  --cert /path/to/cert.pem \\\n  --privkey /path/to/privkey.pem \\\n  --chain-cert /path/to/chain.pem\n```\n\n#### Automatic Chain Certificate Naming:\n\nBy default, the script automatically detects the chain certificate name from the Common Name (CN) in the certificate. For example, Let's Encrypt intermediate certificates like \"R10\", \"R11\", \"E5\", \"E6\" etc. are automatically detected:\n\n```bash\n# Chain name is auto-detected from the certificate CN\nnetscaler-certbot-hook --name example.com\n# Creates/updates chain certificate with name like \"R11\" or \"E6\"\n```\n\n#### Custom Chain Certificate Name:\n\nYou can override the auto-detection and specify a custom chain certificate name:\n\n```bash\nnetscaler-certbot-hook --name example.com --chain my-custom-chain\n```\n\n#### Verbose Output for Debugging:\n\n```bash\n# Enable detailed DEBUG logging\nnetscaler-certbot-hook --name example.com --verbose\n```\n\n#### Quiet Mode for Cron Jobs:\n\n```bash\n# Suppress all output except errors\nnetscaler-certbot-hook --name example.com --quiet\n```\n\n#### Update Chain Certificate:\n\nWhen trust chains change (e.g., Let's Encrypt issuer switching from E8 to E7), use both `--update-chain` and `--no-domain-check` flags:\n\n```bash\n# Allow chain certificate updates when serial differs\nnetscaler-certbot-hook --name example.com --update-chain --no-domain-check\n```\n\n**Note:** By default, the script will refuse to update chain certificates if the serial number differs. This is a security measure to prevent unexpected trust chain changes. Use `--update-chain` only when you are certain the new chain certificate is valid and expected.\n\n**Why `--no-domain-check` is required:** Chain certificates (intermediate CAs) are registered to different domains than your end-entity certificate. Without this flag, NetScaler will reject the update with the error: \"Certificate is registered to a different domain; use the 'no domain check' option to force the operation\".\n\n#### Skip Domain Validation:\n\nThe `--no-domain-check` flag is useful in several scenarios:\n\n```bash\n# Update certificate with domain changes or multi-domain certificates\nnetscaler-certbot-hook --name example.com --no-domain-check\n```\n\n**When to use `--no-domain-check`:**\n- Updating chain/intermediate certificates (required)\n- Certificates with multiple SANs (Subject Alternative Names)\n- Certificates bound to multiple virtual servers\n- When domain names in the certificate have changed\n- Any scenario where NetScaler reports: \"Certificate is registered to a different domain\"\n\n**Technical Details:** This flag passes the `nodomaincheck` parameter to the NetScaler NITRO API, which bypasses domain validation during certificate updates.\n\n### Step 3: Automate with Cron\n\nAdd to your crontab for automatic renewal:\n\n```bash\n# Renew certificates daily and update NetScaler\n0 3 * * * certbot renew --quiet \u0026\u0026 netscaler-certbot-hook --name example.com\n```\n\nOr create a Certbot deploy hook:\n\n```bash\n# /etc/letsencrypt/renewal-hooks/deploy/netscaler-hook.sh\n#!/bin/bash\nexport NS_URL=https://192.168.10.10\nexport NS_LOGIN=nsroot\nexport NS_PASSWORD=your-password\n\nnetscaler-certbot-hook --name $RENEWED_DOMAINS\n```\n\nMake it executable:\n```bash\nchmod +x /etc/letsencrypt/renewal-hooks/deploy/netscaler-hook.sh\n```\n\n## Logging\n\nThe script uses Python's built-in logging framework for structured output. You can control the verbosity with command-line flags:\n\n### Log Levels\n\n| Flag | Log Level | Use Case |\n|------|-----------|----------|\n| *default* | `INFO` | Standard output showing progress |\n| `--verbose` | `DEBUG` | Detailed output for troubleshooting |\n| `--quiet` | `ERROR` | Minimal output, only errors |\n\n### Examples\n\n**Standard Output (INFO level):**\n```bash\nnetscaler-certbot-hook --name example.com\n```\nShows all important operations and their status.\n\n**Verbose Mode (DEBUG level):**\n```bash\nnetscaler-certbot-hook --name example.com --verbose\n```\nShows additional debugging information including:\n- Connection details\n- Configuration values\n- Detailed operation steps\n\n**Quiet Mode (ERROR level):**\n```bash\nnetscaler-certbot-hook --name example.com --quiet\n```\nOnly shows errors. Perfect for cron jobs where you only want to be notified of failures.\n\n### Logging for Cron Jobs\n\nFor automated cron jobs, use `--quiet` to suppress normal output:\n\n```bash\n# Only log errors to file\n0 3 * * * netscaler-certbot-hook --name example.com --quiet 2\u003e\u003e /var/log/netscaler-cert-errors.log\n```\n\nOr use standard output with log rotation:\n\n```bash\n# Log all output with rotation\n0 3 * * * netscaler-certbot-hook --name example.com \u003e\u003e /var/log/netscaler-cert.log 2\u003e\u00261\n```\n\n## Example Output\n\n### Initial Setup\n\nWhen running for the first time:\n\n```\nchain certificate letsencrypt not found\nuploading chain certificate as letsencrypt-1581896753.crt\ninstalling chain certificate with serial 13298795840390663119752826058995181320\ncertificate example.com not found\nuploading certificate as example.com-1581896753.crt\nuploading private key as example.com-1581896753.key\ninstalling certificate with serial 409596789458967997345847308430335698529007\nlink certificate example.com to chain certificate letsencrypt\nsaving configuration\n```\n\n### Certificate Update\n\nWhen certificate has been renewed:\n\n```\nchain certificate letsencrypt found with serial 13298795840390663119752826058995181320\ninstalled chain certificate matches our serial - nothing to do\ncertificate example.com found with serial 409596789458967997345847308430335698529007\nuploading certificate as example.com-1581896812.crt\nuploading private key as example.com-1581896812.key\nupdate certificate example.com\nlink certificate example.com to chain certificate letsencrypt\ncertificate link was already present - nothing to do\nsaving configuration\n```\n\n### No Changes Needed\n\nWhen certificate is already up-to-date:\n\n```\nchain certificate letsencrypt found with serial 13298795840390663119752826058995181320\ninstalled chain certificate matches our serial - nothing to do\ncertificate example.com found with serial 409596789458967997345847308430335698529007\ninstalled certificate matches our serial - nothing to do\n```\n\n## Security Considerations\n\n### Chain Certificate Updates\n\nBy default, the script does **not** automatically update chain certificates if the serial number differs. This prevents potential security issues from unexpected chain updates.\n\n**To enable chain certificate updates**, use the `--update-chain` flag:\n\n```bash\nnetscaler-certbot-hook --name example.com --update-chain\n```\n\n**When to use `--update-chain`:**\n- Let's Encrypt issuer rotation (e.g., switching from E8 to E7)\n- Let's Encrypt root certificate rotation\n- CA intermediate certificate updates\n- Planned trust chain migrations\n\n**Important:** Chain certificate updates typically require both `--update-chain` (to allow the update) and `--no-domain-check` (to bypass domain validation). Example:\n\n```bash\nnetscaler-certbot-hook --name example.com --update-chain --no-domain-check\n```\n\n**Security Warning:** Only use `--update-chain` when you are expecting a chain certificate change and have verified the new certificate is valid. Unexpected chain changes could indicate a security issue.\n\n### Skip Domain Validation (`--no-domain-check`)\n\nThe `--no-domain-check` flag tells NetScaler to skip domain validation when updating certificates. This is necessary in several scenarios:\n\n**Common use cases:**\n- **Chain certificate updates** (required) - Chain certificates are registered to CA domains, not your domain\n- **Multi-domain certificates** - Certificates with multiple SANs may trigger domain validation errors\n- **Certificate rebinding** - Certificates bound to multiple virtual servers\n- **Domain changes** - When updating certificates with modified domain names\n\n**Error message this solves:**\n```\nERROR: Certificate is registered to a different domain; use the 'no domain check' option to force the operation\n```\n\n**Example usage:**\n```bash\n# Update chain certificate (both flags required)\nnetscaler-certbot-hook --name example.com --update-chain --no-domain-check\n\n# Update regular certificate with domain validation issues\nnetscaler-certbot-hook --name example.com --no-domain-check\n```\n\n**Technical Details:** This flag passes the `nodomaincheck` parameter to the NetScaler NITRO API during certificate update operations.\n\n### Credential Management\n\n**Never commit credentials to version control!** Use environment variables or secure credential management:\n\n```bash\n# Store in secure location\necho \"export NS_PASSWORD='your-password'\" \u003e ~/.netscaler-credentials\nchmod 600 ~/.netscaler-credentials\n\n# Source when needed\nsource ~/.netscaler-credentials\n```\n\n### SSL Verification\n\nAlways enable SSL verification in production:\n\n```bash\nexport NS_VERIFY_SSL=true\n```\n\nOnly disable for testing or development environments.\n\n## API Reference\n\nThe script uses the Citrix NetScaler NITRO API. For more information:\n- [NetScaler NITRO API Documentation](https://docs.citrix.com/en-us/citrix-adc/current-release/nitro-api.html)\n\n## Contributing\n\nSee [CONTRIBUTING.md](.github/CONTRIBUTING.md) for guidelines on contributing to this project\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Authors\n\n- **Simon Lauger** - [@slauger](https://github.com/slauger)\n\n## Support\n\nFor issues, questions, or contributions, please use the [GitHub issue tracker](https://github.com/slauger/netscaler-certbot-hook/issues)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fslauger%2Fnetscaler-certbot-hook","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fslauger%2Fnetscaler-certbot-hook","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fslauger%2Fnetscaler-certbot-hook/lists"}