AnyConnect SSL VPN (rebranded as Cisco Secure Client) is the most common remote-access VPN you will configure on a Cisco ASA. It tunnels TLS over TCP/443, which gets through nearly every hotel, airport, and customer-site firewall, and it has a stable Windows / macOS / Linux / iOS / Android client. This article walks through the full configuration on Cisco ASA software 9.x: certificate, IP pool, group-policy, tunnel-group, AAA, and the WebVPN service that ties it all together. Every show command output below is from a live ASAv 9.23(1) in the PingLabz ASA reference lab.
Before you start, confirm three things: the ASA's outside interface has a routable address, you have an identity certificate (or are willing to use a self-signed one), and you have an AnyConnect / Cisco Secure Client package (.pkg) for at least one client OS. The .pkg upload is the one piece that needs a real client image from Cisco's download portal. Everything else is config.
The AnyConnect SSL VPN Building Blocks
Five building blocks have to come together before the first client can connect:
| Block | Purpose | Configured under |
|---|---|---|
| Identity certificate | Server cert presented during the TLS handshake. Clients pin to its CN or SAN. | crypto ca trustpoint + ssl trust-point |
| IP local pool | The pool of inside addresses the ASA hands out to connected clients. | ip local pool |
| Group-policy | The bundle of attributes (DNS, split-tunnel ACL, DPD, banner) pushed to the client. | group-policy NAME internal |
| Tunnel-group (connection profile) | The named connection profile clients select; ties group-policy + AAA + address-pool together. | tunnel-group NAME type remote-access |
| WebVPN service | Enables the SSL listener on the outside interface and turns AnyConnect on. | webvpn global block |
Get any one of those five wrong and the client fails in a different and confusing way. A missing trustpoint produces a TLS handshake error. A missing IP pool produces "user does not have permission to use this connection profile". A wrong group-policy produces a connection that succeeds but lands the client without DNS or routes. The order below builds them in the right sequence so each step has working dependencies.
Step 1: Generate the Identity Certificate
For lab and proof-of-concept work, a self-signed certificate is fine. For production, use an enterprise CA or a public CA so clients do not see certificate warnings.
ASA-PERIM(config)# domain-name pinglabz.lab
ASA-PERIM(config)# crypto key generate rsa label PINGLABZ-RSA modulus 2048 noconfirm
Keypair generation process begin. Please wait...
The RSA keypairs were successfully generated.
ASA-PERIM(config)# crypto ca trustpoint PINGLABZ-SELFSIGNED
ASA-PERIM(config-ca-trustpoint)# enrollment self
ASA-PERIM(config-ca-trustpoint)# fqdn vpn.pinglabz.lab
ASA-PERIM(config-ca-trustpoint)# subject-name CN=vpn.pinglabz.lab,O=PingLabz,C=US
ASA-PERIM(config-ca-trustpoint)# keypair PINGLABZ-RSA
ASA-PERIM(config-ca-trustpoint)# exit
ASA-PERIM(config)# crypto ca enroll PINGLABZ-SELFSIGNED noconfirm
% The fully-qualified domain name in the certificate will be: vpn.pinglabz.lab
ASA-PERIM(config)# ssl trust-point PINGLABZ-SELFSIGNED outside
Verify with show crypto ca certificates:
ASA-PERIM# show crypto ca certificates
...
Certificate
Status: Available
Certificate Serial Number: 69ffc240
Certificate Usage: General Purpose
Public Key Type: RSA (2048 bits)
Signature Algorithm: RSA-SHA256
Issuer Name:
unstructuredName=vpn.pinglabz.lab
C=US
O=PingLabz
CN=vpn.pinglabz.lab
Subject Name:
unstructuredName=vpn.pinglabz.lab
C=US
O=PingLabz
CN=vpn.pinglabz.lab
Validity Date:
start date: 00:37:39 UTC May 10 2026
end date: 00:37:39 UTC May 7 2036
Storage: config
Associated Trustpoints: PINGLABZ-SELFSIGNED
That is the cert clients will see on TLS handshake. The fact that issuer and subject are identical is what makes it self-signed. Note the 10-year validity (CA defaults to 1 year on enrollment for a real CA, but a self-signed cert defaults to 10 years on the ASA). If you want a CA-signed cert, the trustpoint enrollment changes from self to terminal or url, and you import the issuer chain. We cover the full cert workflow in Cisco ASA Certificate Management for AnyConnect.
Step 2: Create the Client IP Pool and a Local User
AnyConnect clients need an inside address. Carve out a separate /24 (or larger) that is not in use anywhere else and is routable from the inside network. In our lab we use 10.99.99.0/24 because it does not collide with the inside 10.10.0.0/16.
ASA-PERIM(config)# ip local pool VPN-POOL 10.99.99.10-10.99.99.250 mask 255.255.255.0
ASA-PERIM(config)# username vpnuser password PingLabzVPN! privilege 0
ASA-PERIM(config)# username vpnuser attributes
ASA-PERIM(config-username)# service-type remote-access
ASA-PERIM(config-username)# exit
The service-type remote-access line is important. Without it, that local user can shell into the ASA via SSH (priv 0 only, but still). With it, the user can authenticate for VPN but is rejected for SSH and ASDM.
Verify the pool:
ASA-PERIM# show ip local pool VPN-POOL
Begin End Mask Free Held In use
10.99.99.10 10.99.99.250 255.255.255.0 241 0 0
241 addresses available, none assigned yet. Each connected client gets one until disconnected, at which point the address goes back to the pool after the idle timeout.
Step 3: Build the Group-Policy
The group-policy is the bag of attributes the ASA pushes to the client at login: which DNS servers, which split-tunnel ACL, what banner, DPD intervals, and most importantly which tunnel protocol(s) the client is allowed to use.
ASA-PERIM(config)# access-list SPLIT-TUNNEL standard permit 10.10.0.0 255.255.0.0
ASA-PERIM(config)# group-policy ANYCONNECT-SSL-GP internal
ASA-PERIM(config)# group-policy ANYCONNECT-SSL-GP attributes
ASA-PERIM(config-group-policy)# vpn-tunnel-protocol ssl-client
ASA-PERIM(config-group-policy)# split-tunnel-policy tunnelspecified
ASA-PERIM(config-group-policy)# split-tunnel-network-list value SPLIT-TUNNEL
ASA-PERIM(config-group-policy)# dns-server value 10.10.0.10
ASA-PERIM(config-group-policy)# default-domain value pinglabz.lab
ASA-PERIM(config-group-policy)# webvpn
ASA-PERIM(config-group-webvpn)# anyconnect keep-installer installed
ASA-PERIM(config-group-webvpn)# anyconnect ssl dtls enable
ASA-PERIM(config-group-webvpn)# anyconnect ssl rekey time 60
ASA-PERIM(config-group-webvpn)# anyconnect ssl rekey method ssl
ASA-PERIM(config-group-webvpn)# anyconnect dpd-interval client 30
ASA-PERIM(config-group-webvpn)# anyconnect dpd-interval gateway 30
ASA-PERIM(config-group-webvpn)# exit
A few of those lines deserve called-out attention:
vpn-tunnel-protocol ssl-client: this group-policy only permits the SSL client. If the user attempts to use IKEv2, the connection is rejected. A separate group-policy for IKEv2 lets you keep the two profiles cleanly separated. We cover IKEv2 client setup in Cisco ASA AnyConnect IKEv2 VPN Configuration.split-tunnel-policy tunnelspecified: only traffic destined to the networks in the SPLIT-TUNNEL ACL is sent through the VPN. Everything else (Netflix, Google, the public internet) goes direct. The other choices aretunnelall(all traffic via VPN) andexcludespecified. Full details in Cisco ASA Split Tunneling Explained.anyconnect ssl dtls enable: the client opens a UDP DTLS channel in parallel to the TCP channel. UDP is much faster for video and large transfers because TCP-over-TCP gets bogged down in nested retransmits.anyconnect dpd-interval: dead-peer-detection. Both sides probe every 30 seconds; if 4 misses, the tunnel is torn down and the client reconnects.
Step 4: Tunnel-Group (Connection Profile)
The tunnel-group is the named profile clients select. It binds together address pool, group-policy, AAA servers, and (optionally) a custom URL or display alias.
ASA-PERIM(config)# tunnel-group SSL_PROFILE type remote-access
ASA-PERIM(config)# tunnel-group SSL_PROFILE general-attributes
ASA-PERIM(config-tunnel-general)# default-group-policy ANYCONNECT-SSL-GP
ASA-PERIM(config-tunnel-general)# address-pool VPN-POOL
ASA-PERIM(config-tunnel-general)# authentication-server-group RADIUS-VPN LOCAL
ASA-PERIM(config-tunnel-general)# exit
ASA-PERIM(config)# tunnel-group SSL_PROFILE webvpn-attributes
ASA-PERIM(config-tunnel-webvpn)# group-alias EMPLOYEES enable
ASA-PERIM(config-tunnel-webvpn)# group-url https://203.0.113.2/employees enable
ASA-PERIM(config-tunnel-webvpn)# exit
The authentication-server-group RADIUS-VPN LOCAL line authenticates against RADIUS first, falling back to the local username database if RADIUS is unreachable. We covered the AAA server setup in detail in Cisco ASA AAA for VPN: LDAP, RADIUS, and TACACS+.
The two webvpn-attribute lines control how clients see the connection profile:
group-alias EMPLOYEES enable: the dropdown at https://203.0.113.2/ shows "EMPLOYEES" as a selectable profile.group-url https://203.0.113.2/employees enable: clients hitting that exact URL automatically land on this profile without choosing.
A common pattern is to publish a different group-url for each org unit (employees, contractors, partners). Each maps to a different group-policy with a different split-tunnel ACL and a different banner.
Step 5: Enable WebVPN and AnyConnect Globally
Even with everything above configured, no SSL listener is running on the outside interface until you enable WebVPN. This is the global service that owns the TLS endpoint on TCP/443.
ASA-PERIM(config)# webvpn
ASA-PERIM(config-webvpn)# enable outside
INFO: WebVPN and DTLS are enabled on 'outside'.
ASA-PERIM(config-webvpn)# anyconnect enable
WARNING: No 'anyconnect image' commands have been issued
ASA-PERIM(config-webvpn)# tunnel-group-list enable
ASA-PERIM(config-webvpn)# exit
The warning about no anyconnect image command means the client package upload step is missing. In production you would copy the .pkg to flash and reference it:
ASA-PERIM(config-webvpn)# anyconnect image flash:/cisco-secure-client-win-5.1.10.233-webdeploy-k9.pkg 1
Without the image, browsers can land on the portal page but the AnyConnect client cannot auto-download. In our lab we leave it absent because we do not have a real client image, and we are exercising the configuration plane only. The control plane is fully functional regardless of whether the .pkg is present, which is what matters for verifying the config is correct.
Verification: Did Everything Take?
Three quick sanity-check commands:
ASA-PERIM# show ssl
Accept connections using SSLv3 or greater and negotiate to TLSv1.2 or greater
Start connections using TLSv1.2 and negotiate to TLSv1.2 or greater
SSL DH Group: group14 (2048-bit modulus, FIPS)
SSL ECDH Group: group19 (256-bit EC)
SSL trust-points:
Self-signed (RSA 2048 bits RSA-SHA256) certificate available
Self-signed (EC 256 bits ecdsa-with-SHA256) certificate available
Interface outside: PINGLABZ-SELFSIGNED (RSA 2048 bits RSA-SHA256)
Certificate authentication is not enabled
ASA-PERIM# show webvpn anyconnect
AnyConnect Client is enabled. No images configured
ASA-PERIM# show vpn-sessiondb anyconnect
INFO: There are presently no active sessions of the type specified
The first output confirms our trustpoint is bound to the outside interface. The second confirms AnyConnect is on but no client image is uploaded (the lab constraint). The third just shows there are no active sessions, which is the expected state until a client connects.
Once a real client connects, show vpn-sessiondb anyconnect displays the session, the assigned IP from the pool, the encryption suite, the bytes transferred, and the duration. show vpn-sessiondb summary rolls those stats up for capacity planning.
Common Gotchas
The five mistakes that catch every engineer once:
- Trustpoint bound to the wrong interface. If
ssl trust-point PINGLABZ-SELFSIGNED outsideis missing or points at the inside, clients see the default ASA self-signed cert and warn about a CN mismatch. Always bind the trustpoint to the interface the clients will hit. - NAT exemption not configured for the VPN pool. If 10.99.99.0/24 traffic to the inside subnet gets PAT-translated by your existing dynamic PAT rule, clients connect successfully but cannot reach inside resources because the return traffic goes to the wrong source. Fix with an identity NAT rule in Section 1. Full walkthrough in Cisco ASA Identity NAT / NAT Exemption for VPNs.
- Split-tunnel ACL is extended instead of standard. The
split-tunnel-network-listattribute requires a standard ACL. Pasting an extended ACL silently fails to apply, and the client getstunnelallbehavior by default. - Group-policy default-domain or DNS missing. Clients connect but cannot resolve
fileserver.pinglabz.labshort names. Always setdns-serveranddefault-domainin the group-policy. - Outside ACL blocking TCP/443 from the internet. If your
OUTSIDE_INACL has an explicit deny near the top, the SSL handshake never reaches the WebVPN service. Check with packet-tracer to see if the ACL phase is dropping the SYN.
Key Takeaways
AnyConnect SSL VPN on Cisco ASA breaks down into five building blocks: the identity certificate, the IP local pool, the group-policy, the tunnel-group connection profile, and the WebVPN service. Build them in that order and each step has the dependencies it needs. The trickiest piece for first-time setups is binding the trustpoint to the right interface and remembering to add NAT exemption for the VPN pool, both of which produce silent failures rather than clear errors.
For the full Cisco ASA reference, including site-to-site IPsec, NAT, ACLs, failover, and troubleshooting tools, see the Cisco ASA pillar. When connections fail, start with Troubleshoot AnyConnect Login and Certificate Problems on ASA; for the ACL side, Cisco ASA ACL Troubleshooting with packet-tracer covers the most common drops.