8.9 KiB
SSL Management Project
This project provides utilities for managing SSL certificates for UniFi devices such as UDM-SE. The tool helps automate the process of obtaining, validating, and deploying SSL certificates to UniFi devices.
Development
Development for this project is done on the PortForwarding branch. The master branch is reserved for stable releases.
Features
- Check certificate expiration dates
- Validate certificate chains
- Generate self-signed certificates for testing
- Deploy certificates to UniFi devices
- Check port connectivity for troubleshooting Let's Encrypt validation issues
- Automatic port forwarding from UniFi host to local machine when needed
Configuration
The project uses a configuration file (config.json) to store default settings. See the guidelines document for more information.
Usage
Check Certificate Expiration
python src/ssl_manager.py check example.com [--port PORT]
Generate Certificate
python src/ssl_manager.py generate [COMMON_NAME] [--type TYPE] [--days DAYS] [--email EMAIL] [--validation-method METHOD] [--staging|--production] [--skip-port-check]
Options:
COMMON_NAME: The domain name for the certificate (defaults to UniFi host from config)--type: Type of certificate to generate (self-signedorletsencrypt, default:letsencrypt)--days: Days valid (for self-signed certificates only, overrides config)--email: Email address for Let's Encrypt registration--validation-method: Method to use for domain validation (standalone,webroot, ordns)--staging: Use Let's Encrypt's staging environment for testing--production: Use Let's Encrypt's production environment--skip-port-check: Skip checking if required ports are open before certificate generation
Local Machine Identity and Port Check
IMPORTANT: For Let's Encrypt validation to work, the required ports must be open on the machine running this script, not necessarily the target server for which the certificate is being generated.
The tool now automatically identifies the local machine (hostname, IP addresses) and checks if the required ports are open on this machine before attempting certificate generation. This is crucial because:
- Let's Encrypt's validation server connects to the machine running this script
- The domain name in the certificate doesn't have to resolve to the same machine
- Port forwarding may be required if your machine is behind a router/NAT
Example output showing local machine information:
Local Machine Information:
Hostname: server1
Public IP(s): 203.0.113.10
Private IP(s): 192.168.1.100, 10.0.0.5
Note: The domain example.com does not resolve to this machine.
For Let's Encrypt validation, the required ports must be open on THIS machine.
Checking port connectivity on local machine before certificate generation...
Port Connectivity Results for localhost:
--------------------------------------------------
Port 80: ✗ CLOSED - Connection failed
Error: Some required ports are closed on the local machine. Let's Encrypt certificate generation will fail.
For Let's Encrypt validation to work, the validation port must be accessible from the internet.
The standalone validation method requires port 80 to be open on THIS machine.
Consider:
1. Opening port 80 in your firewall
2. Setting up port forwarding on your router to forward external port 80 to this machine
3. Using a different validation method (--validation-method dns)
4. Configuring a different HTTP port in your config file (letsencrypt.http_port)
The port check is tailored to the validation method being used:
- Standalone validation: Checks if the HTTP port (80 or configured port) is open on the local machine
- Webroot validation: Checks if port 80 is open on the local machine
- DNS validation: No ports need to be checked
If you want to skip the port check, use the --skip-port-check option:
python src/ssl_manager.py generate example.com --skip-port-check
Automatic Port Forwarding
When the local machine running the script is different from the UniFi host specified in the config file, and the required ports are closed on the local machine, the tool can automatically set up port forwarding from the UniFi host to the local machine.
This feature requires the paramiko Python package for SSH functionality:
pip install paramiko
How it works:
- The tool checks if the required ports are open on the local machine
- If ports are closed and the local machine is different from the UniFi host, it attempts to set up port forwarding
- It establishes an SSH connection to the UniFi host using the SSH parameters from the config file
- It identifies the local machine's IP address, prioritizing 192.168.x.x addresses when available
- It sets up port forwarding for each closed port from the UniFi host to the local machine
- It rechecks the ports to see if they're now accessible
- When certificate generation is complete (successful or not), it automatically removes the port forwarding rules
Example output when port forwarding is used:
Local Machine Information:
Hostname: server1
Public IP(s): 203.0.113.10
Private IP(s): 192.168.1.100, 10.0.0.5
Checking port connectivity on local machine before certificate generation...
Port Connectivity Results for localhost:
--------------------------------------------------
Port 80: ✗ CLOSED - Connection failed
Local machine is different from UniFi host (unifi.example.com).
Attempting to set up port forwarding from UniFi host to local machine...
Port forwarding set up successfully. Rechecking ports...
Port Connectivity Results for localhost:
--------------------------------------------------
Port 80: ✓ OPEN - Connected (not SSL/TLS)
All required ports are now open with port forwarding.
[Certificate generation proceeds...]
Cleaning up port forwarding rules...
Port forwarding cleanup complete.
This feature is particularly useful when:
- Your local machine is behind a firewall or NAT that blocks incoming connections
- You don't have administrative access to configure port forwarding on your router
- The UniFi host is publicly accessible and can receive incoming connections
If the automatic port forwarding doesn't work, you can still:
- Manually set up port forwarding on your router
- Use DNS validation instead (
--validation-method dns) - Run the script directly on the UniFi host if possible
Validate Certificate Chain
python src/ssl_manager.py validate path/to/certificate.crt [--ca-path path/to/ca.crt]
Check Port Connectivity
The check-ports command helps diagnose connectivity issues that might prevent successful Let's Encrypt certificate generation. It uses OpenSSL's s_client to check if ports are open and accessible, and determines the SSL/TLS status of each port.
python src/ssl_manager.py check-ports [HOSTNAME] [--ports PORT1 PORT2 ...] [--timeout SECONDS]
Options:
HOSTNAME: The hostname to check (defaults to UniFi host from config)--ports,-p: Specific ports to check (default: 443, 80, and the configured Let's Encrypt HTTP port)--timeout,-t: Timeout in seconds for each connection attempt (default: 10)
Example:
python src/ssl_manager.py check-ports example.com --ports 443 80 8080
Output example with local machine information:
Local Machine Information:
Hostname: server1
Public IP(s): 203.0.113.10
Private IP(s): 192.168.1.100, 10.0.0.5
Checking port connectivity for example.com...
Port Connectivity Results for example.com:
--------------------------------------------------
Port 80: ✓ OPEN - Connected (not SSL/TLS)
Port 443: ✓ OPEN - SSL Error: self-signed certificate (code 18)
Port 8080: ✓ OPEN - Connected (not SSL/TLS)
Troubleshooting Let's Encrypt with Port Checker
If you're having issues with Let's Encrypt certificate generation, use the check-ports command to verify that the necessary ports are open and accessible on your local machine:
-
For standalone validation, check that the configured HTTP port (default: 80) is open on your local machine:
python src/ssl_manager.py check-ports localhost --ports 80 -
If using a non-standard HTTP port (e.g., 8080), check that port instead:
python src/ssl_manager.py check-ports localhost --ports 8080 -
If ports are shown as closed, ensure they are open in your firewall and accessible from the internet:
- Open the required ports in your local firewall
- Set up port forwarding on your router if you're behind NAT
- Verify that your ISP doesn't block the required ports
-
If Let's Encrypt validation fails despite open ports, consider using DNS validation which doesn't require open ports:
python src/ssl_manager.py generate your-domain.com --validation-method dns
Remember that Let's Encrypt's validation server connects to the machine running this script, so the ports must be open on your local machine and accessible from the internet.