Prerequisites
Before you start creating SSL profiles on the BIG-IP, a few things need to be in place. First, you need a valid SSL certificate and its corresponding private key. These should be signed by a trusted CA — either a public CA or your internal PKI. If you're using a certificate chain (which you almost always will be in production), you'll also need the intermediate and root CA certificates in a bundle file.
On the BIG-IP side, you need at minimum:
- BIG-IP LTM licensed and provisioned
- Administrative access — either via the GUI at
https://192.168.10.1
or over SSH asinfrarunbook-admin
- A virtual server already configured, or at least a pool and nodes ready to attach the SSL profiles to
- The certificate, key, and CA bundle files staged and ready to import into the BIG-IP certificate store
I'd also strongly recommend having an OpenSSL-capable Linux host on hand so you can verify the SSL handshake from outside the F5 once the profiles are live. Troubleshooting blind is no fun.
Understanding Client vs. Server SSL Profiles
This trips people up constantly, so let's be explicit. A Client SSL profile handles the SSL connection between the client — browser, application, API consumer, whatever is hitting your VIP — and the BIG-IP itself. The BIG-IP terminates that SSL session. The Server SSL profile handles the connection between the BIG-IP and the back-end pool members. If you're re-encrypting traffic on its way to the servers, you need a Server SSL profile.
You can run Client SSL only — SSL offload, where decrypted traffic hits the servers over plain HTTP. You can run both Client and Server SSL — SSL bridging or re-encryption, where the F5 decrypts, potentially inspects, then re-encrypts to the servers. What you almost never want is Server SSL without Client SSL, unless you're doing something unusual like gateway mode. Keep that mental model clear before you touch anything.
Importing Certificates and Keys
Before you can build the profiles, the certificates need to live in the BIG-IP's certificate store. You can do this via the GUI under System > Certificate Management > Traffic Certificate Management, or via tmsh. I prefer tmsh for repeatability — GUI clicks don't go in a runbook very well, and they don't survive config audits either.
Copy your certificate, key, and CA bundle files to the BIG-IP:
scp solvethenetwork.com.crt infrarunbook-admin@192.168.10.1:/var/tmp/
scp solvethenetwork.com.key infrarunbook-admin@192.168.10.1:/var/tmp/
scp solvethenetwork-ca-bundle.crt infrarunbook-admin@192.168.10.1:/var/tmp/
Then SSH into the BIG-IP and import them:
tmsh install sys crypto cert solvethenetwork-2025 from-local-file /var/tmp/solvethenetwork.com.crt
tmsh install sys crypto key solvethenetwork-2025 from-local-file /var/tmp/solvethenetwork.com.key
tmsh install sys crypto cert solvethenetwork-ca-bundle from-local-file /var/tmp/solvethenetwork-ca-bundle.crt
Verify they landed correctly:
tmsh list sys crypto cert solvethenetwork-2025
tmsh list sys crypto key solvethenetwork-2025
If the list commands return output with the expected subject and expiry, you're good. If either returns an error, the import failed — usually because the file path is wrong or the file is malformed. Check it with
openssl x509 -in /var/tmp/solvethenetwork.com.crt -noout -textbefore retrying.
Step 1 — Creating the Client SSL Profile
The Client SSL profile is where most of the heavy lifting happens. This is what clients negotiate with, so your cipher suite selection, certificate presentation, and SNI configuration all live here.
Via tmsh, create the Client SSL profile like this:
tmsh create ltm profile client-ssl solvethenetwork-clientssl {
cert-key-chain {
solvethenetwork-2025 {
cert solvethenetwork-2025.crt
key solvethenetwork-2025.key
chain solvethenetwork-ca-bundle.crt
}
}
ciphers "ECDHE+AESGCM:ECDHE+AES256:!RC4:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP"
options { dont-insert-empty-fragments no-tlsv1 no-sslv3 no-tlsv1-1 }
sni-default true
defaults-from clientssl
}
Let me walk through the key parameters. The
cert-key-chainblock references the objects you just imported — cert, key, and chain all in one named entry. The
chainfield is your CA bundle. Don't skip it. Clients that don't have your intermediate CA cached will fail validation, and that includes most mobile apps and API clients that don't do AIA fetching.
The
ciphersstring uses OpenSSL-style cipher notation. The example above disables RC4, null ciphers, export-grade ciphers, and 3DES while preferring ECDHE-based suites with AES-GCM. This is a solid baseline for most environments in 2025.
The
optionsblock controls protocol versions.
no-tlsv1and
no-tlsv1-1disable TLS 1.0 and 1.1, enforcing TLS 1.2 as the minimum.
no-sslv3disables SSL 3.0 entirely. If you still have legacy clients that require TLS 1.0 or 1.1, you'll need to remove those options — but document why and get sign-off, because you're making a deliberate security concession.
dont-insert-empty-fragmentsis a legacy workaround for certain older TLS implementations and is generally fine to leave in.
The
defaults-from clientsslline means this custom profile inherits all unset parameters from the built-in
clientsslparent profile. Always use the built-in parent unless you have a very specific reason not to. Inheriting from another custom profile stacks up configuration layers that become impossible to reason about when something breaks at 2am.
Setting
sni-default truedesignates this profile as the fallback when a client doesn't send a Server Name Indication in the ClientHello. If you plan to have multiple certificate/key pairs under the same VIP for different hostnames, this is the one that answers when no SNI match is found. For a single-domain VIP, you still want this set to true.
Step 2 — Creating the Server SSL Profile
The Server SSL profile controls how the BIG-IP establishes its outbound connection to your back-end pool members. If you're doing SSL offload — plain HTTP to the servers — you skip this entirely. But if your servers require HTTPS, which is increasingly the norm for compliance reasons, you need this profile.
tmsh create ltm profile server-ssl solvethenetwork-serverssl {
ciphers "ECDHE+AESGCM:ECDHE+AES256:!RC4:!aNULL:!eNULL:!LOW:!3DES"
options { dont-insert-empty-fragments no-tlsv1 no-sslv3 }
peer-cert-mode ignore
server-name www.solvethenetwork.com
defaults-from serverssl
}
The
peer-cert-modesetting controls whether the BIG-IP validates the server's certificate. Setting it to
ignoremeans no validation happens — which sounds insecure, but is actually common in internal environments where servers use self-signed certificates or an internal PKI that the BIG-IP doesn't have a trust anchor for. In my experience, most internal deployments start here and tighten up later.
If you want the BIG-IP to actually authenticate the server certificate, set
peer-cert-mode requireand configure the CA bundle the server cert was signed by:
tmsh modify ltm profile server-ssl solvethenetwork-serverssl {
peer-cert-mode require
ca-file solvethenetwork-ca-bundle.crt
}
The
server-namefield sends an SNI hostname in the BIG-IP's outbound ClientHello to the server. If your back-end servers host multiple certificates on the same IP and port, this tells them which certificate to present. Match this to the FQDN the server expects — typically the same hostname your clients use to reach the VIP, unless you're doing host header rewriting.
Step 3 — Attaching Profiles to the Virtual Server
With both profiles created, attach them to your virtual server. The virtual server must be a Standard type — Performance Layer 4 and FastL4 virtual servers bypass the full proxy stack and can't do SSL termination. If you're not sure what type your VS is, check with
tmsh list ltm virtual vs_solvethenetwork_443 | grep type.
tmsh modify ltm virtual vs_solvethenetwork_443 {
profiles add {
solvethenetwork-clientssl { context clientside }
solvethenetwork-serverssl { context serverside }
http { }
tcp { }
}
}
The
context clientsideand
context serversideassignments are mandatory for SSL profiles. Without them, the BIG-IP doesn't know which side of the proxy to apply the profile to and will reject the configuration. The
httpprofile is there because once you're terminating SSL, you almost always want L7 HTTP awareness — access to headers, URI, host for persistence and iRule logic, plus proper HTTP logging.
Full Configuration Example
Here's the complete tmsh configuration in a single block, suitable for a runbook or a configuration script. This assumes the virtual server already exists at 192.168.10.100:443 with an associated pool.
# Import certificates and keys
install sys crypto cert solvethenetwork-2025 from-local-file /var/tmp/solvethenetwork.com.crt
install sys crypto key solvethenetwork-2025 from-local-file /var/tmp/solvethenetwork.com.key
install sys crypto cert solvethenetwork-ca-bundle from-local-file /var/tmp/solvethenetwork-ca-bundle.crt
# Create Client SSL Profile
create ltm profile client-ssl solvethenetwork-clientssl {
cert-key-chain {
solvethenetwork-2025 {
cert solvethenetwork-2025.crt
key solvethenetwork-2025.key
chain solvethenetwork-ca-bundle.crt
}
}
ciphers "ECDHE+AESGCM:ECDHE+AES256:!RC4:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP"
options { dont-insert-empty-fragments no-tlsv1 no-sslv3 no-tlsv1-1 }
sni-default true
defaults-from clientssl
}
# Create Server SSL Profile
create ltm profile server-ssl solvethenetwork-serverssl {
ciphers "ECDHE+AESGCM:ECDHE+AES256:!RC4:!aNULL:!eNULL:!LOW:!3DES"
options { dont-insert-empty-fragments no-tlsv1 no-sslv3 }
peer-cert-mode ignore
server-name www.solvethenetwork.com
defaults-from serverssl
}
# Attach profiles to the Virtual Server
modify ltm virtual vs_solvethenetwork_443 {
destination 192.168.10.100:443
ip-protocol tcp
profiles add {
solvethenetwork-clientssl { context clientside }
solvethenetwork-serverssl { context serverside }
http { }
tcp { }
}
pool pool_solvethenetwork_web
source-address-translation {
type automap
}
}
# Save configuration to disk
save sys config
That last line matters more than people think. The BIG-IP does not auto-save on configuration changes. I've seen engineers make a dozen changes during an incident, test successfully, then watch everything revert after a chassis failover because the config was never committed to disk.
save sys configis not optional.
Verification Steps
Once the profiles are attached and the config is saved, verify it works. Don't assume the absence of errors means everything is correct — test the actual SSL handshake.
Verify the Handshake with OpenSSL
From a Linux host that can reach the VIP, run:
openssl s_client -connect 192.168.10.100:443 -servername www.solvethenetwork.com
Read the output carefully. You want to see the full certificate chain returned — server cert first, followed by the intermediates. The session should end with
Verify return code: 0 (ok). If you get code 20 (unable to get local issuer certificate) or code 21 (unable to verify the first certificate), your
chainparameter in the Client SSL profile is either wrong or missing entirely.
To check specifically which TLS version and cipher were negotiated:
openssl s_client -connect 192.168.10.100:443 -servername www.solvethenetwork.com 2>&1 | grep -E "Protocol|Cipher"
Expected output looks something like this:
Protocol : TLSv1.2
Cipher : ECDHE-RSA-AES256-GCM-SHA384
If you see TLSv1 or TLSv1.1, your options block didn't apply — double-check the profile is actually attached to the virtual server and that you saved the config.
Check BIG-IP SSL Statistics
After a few test connections, pull profile-level statistics from the BIG-IP:
tmsh show ltm profile client-ssl solvethenetwork-clientssl
This shows handshake counts, cipher negotiation breakdown, and — critically — handshake failure counts. If failures are non-zero and climbing after your initial tests, that's your first signal to look at cipher compatibility or certificate validity.
You can also pull virtual server-level SSL stats:
tmsh show ltm virtual vs_solvethenetwork_443 detail | grep -i ssl
Test the Server-Side Connection
To verify the BIG-IP can establish its outbound SSL connection to the pool members, test from the BIG-IP CLI directly:
curl -vk https://192.168.10.50/ --resolve www.solvethenetwork.com:443:192.168.10.50
This simulates what the Server SSL profile will do when the BIG-IP connects to a pool member at 192.168.10.50. The
-kflag skips certificate validation here, which is intentional — you're testing TCP and SSL connectivity, not certificate trust. If this curl fails but the pool member is up and listening on 443, look at your Server SSL cipher string or check whether the server requires a minimum TLS version your profile doesn't support.
Common Mistakes
Not including the certificate chain. This is the single most common mistake I see. The
chainfield inside
cert-key-chainis where your intermediate CA certificate or bundle goes. Without it, clients that haven't previously cached your intermediate CA will get an untrusted certificate error — even if the cert itself is perfectly valid. Modern browsers often recover via AIA fetching, but mobile apps, IoT devices, and API clients generally don't. Always include the full chain.
Mixing old-style and new-style certificate configuration. Older BIG-IP configs used top-level
cert,
key, and
chainparameters directly in the profile. Current versions use the
cert-key-chainblock. If you're adapting configs from older runbooks or copying from the F5 docs without checking the version, you can end up with a profile that looks correct but doesn't behave correctly. After creating any SSL profile, always run
tmsh list ltm profile client-ssl solvethenetwork-clientssland read back what was actually stored.
Wrong parent profile. Always inherit Client SSL profiles from the built-in
clientssland Server SSL profiles from the built-in
serverssl. Using
clientssl-secureas the parent is reasonable for high-security environments — it enforces stricter defaults — but you need to know exactly what defaults you're inheriting. I've seen engineers accidentally chain custom profiles from other custom profiles, creating layers of conflicting settings that took hours to unwind during a maintenance window.
Forgetting to specify context on the virtual server. When you attach an SSL profile to a virtual server, the
context clientsideor
context serversideassignment is not optional. If you omit it, the BIG-IP will throw an error, or in older firmware versions, silently ignore the profile. Always be explicit.
Cipher mismatch with back-end servers. In my experience, Server SSL profile issues are almost always cipher-related. Legacy Java applications, older Node.js services, and some embedded devices support a limited cipher set. If your Server SSL profile is too restrictive, the BIG-IP will fail to establish the server-side connection and your pool members will appear down in the monitor stats even though the servers themselves are healthy. Start with a more permissive cipher string on the server side, confirm connectivity, then tighten from there.
No certificate expiry monitoring. The BIG-IP doesn't alert you by default when a certificate is approaching expiry. This has caused outages in every organization I've worked in at least once. Wire up expiry alerting — either via your monitoring platform querying the BIG-IP's certificate objects, or a scheduled OpenSSL check against the VIP itself. An expired certificate on a production load balancer is an entirely preventable incident.
A Note on BIG-IP 15.x and Cipher Groups
If you're running BIG-IP 15.1 or later, F5 introduced named cipher groups as a replacement for raw OpenSSL cipher strings. Instead of an inline string in the profile, you define a
ltm cipher groupobject and reference it from the profile. The approach is the same conceptually — you're still building a Client SSL profile with specific protocol and cipher restrictions — but the configuration syntax is cleaner and cipher policies become reusable across profiles. Worth knowing about if you're managing multiple virtual servers with consistent cipher requirements or working toward PCI-DSS or FedRAMP compliance where cipher policy needs to be documented and auditable.
