--- title: SSL Certificates description: Get and renew TLS certificates for the 3x-ui panel and inbounds — with the x-ui ACME menu (domain or bare IP), a Cloudflare DNS-01 wildcard, or manual Certbot. icon: ShieldCheck --- A TLS certificate lets you serve the **panel** over HTTPS (so your login and API traffic are encrypted) and terminate TLS on **inbounds** (VLESS-TLS, Trojan, Shadowsocks-TLS, and friends). There are three ways to obtain one: - **The `x-ui` menu** — built-in [ACME](https://en.wikipedia.org/wiki/Automatic_Certificate_Management_Environment) client. Easiest for a single domain or a bare IP. - **Cloudflare DNS-01** — also from the menu; needed for **wildcard** certs or when port 80 is blocked / the server sits behind Cloudflare's proxy. - **Manual Certbot** — if you'd rather manage `acme.sh`/Certbot yourself. If you put the panel behind Nginx or Caddy, let the proxy handle the certificate instead — see [Reverse proxy](/docs/operations/reverse-proxy). [REALITY](/docs/config/reality) inbounds need **no** certificate at all; they borrow a real site's TLS. This page is for the panel and for classic TLS inbounds. ## The `x-ui` SSL menu (Let's Encrypt) Run `x-ui` and choose **`20` — SSL Certificate Management**. It drives [acme.sh](https://github.com/acmesh-official/acme.sh) and offers: | Option | What it does | | ------------------------------ | ------------------------------------------------------------------- | | Get SSL (Domain) | Issue a certificate for a domain via HTTP validation. | | Get SSL for IP Address | Issue a short-lived (6-day, auto-renewing) cert for a **bare IP**. | | Revoke | Revoke an existing certificate. | | Force Renew | Renew now, before expiry. | | Show Existing Domains | List certificates already on the server. | | Set Cert paths for the panel | Point the panel's TLS at an issued cert (sets the fields for you). | ### Issue a certificate for a domain ### Point the domain at the server Create an `A` (and/or `AAAA`) record for your domain that resolves to this server's public IP. Validation fails until DNS has propagated. ### Free up port 80 HTTP validation needs **port 80** reachable from the internet and not already in use. Stop anything bound to it for the duration, and allow it through the [firewall](/docs/reference/ports-firewall). ### Run the issuer `x-ui` → `20` → **Get SSL (Domain)**, then enter the domain. acme.sh requests the certificate and saves it under `/root/cert//` as `fullchain.pem` (the certificate chain) and `privkey.pem` (the private key). ### Wire it into the panel Choose **Set Cert paths for the panel** to fill in `webCertFile` and `webKeyFile` and restart the panel, or set them yourself in [Panel Settings](/docs/config/panel#tls). The panel serves HTTPS as soon as both are set. ### Issue a certificate for a bare IP No domain? Choose **Get SSL for IP Address** to obtain a short-lived certificate (valid ~6 days, renewed automatically) bound to the server's IP. Useful for reaching the panel over HTTPS before you've set up a domain. ## Cloudflare (DNS-01 wildcard) DNS validation proves you control the domain by creating a TXT record instead of answering on port 80 — so it works **behind Cloudflare's proxy**, on servers where port 80 is blocked, and for **wildcard** certificates (`*.example.com`). Your domain's DNS must be managed by Cloudflare, and you need one of: - a **scoped API token** with the `Zone:DNS:Edit` permission (recommended), or - your account **email + Global API Key**. ### Create a scoped API token In the Cloudflare dashboard go to **My Profile → API Tokens → [Create Token](https://dash.cloudflare.com/profile/api-tokens)**, pick the **Edit zone DNS** template, scope it to the zone you're issuing for, and create it. Copy the token — it's shown only once. ### Run the Cloudflare issuer `x-ui` → **`21` — Cloudflare SSL Certificate**. When asked, choose **`t`** for an API token (the default) or **`g`** for the Global API Key, then enter your domain (and, for the Global API Key, your account email and key). acme.sh creates the TXT record, validates, and cleans it up. ### Point the panel at it As with the domain flow, use **Set Cert paths for the panel** (menu `20`) or set `webCertFile` / `webKeyFile` in [Panel Settings](/docs/config/panel#tls). Prefer a scoped token over the Global API Key — it only grants DNS edits on the zone you choose, so a leak can't touch the rest of your Cloudflare account. ## Manual (Certbot) If you'd rather not use the menu, issue a certificate with Certbot's standalone plugin (again, this needs port 80 free and the domain resolving to the server): ```bash apt-get install certbot -y certbot certonly --standalone --agree-tos --register-unsafely-without-email -d yourdomain.com certbot renew --dry-run ``` Certbot writes the certificate to `/etc/letsencrypt/live/yourdomain.com/` (`fullchain.pem` and `privkey.pem`). Point the panel at those two files in [Panel Settings](/docs/config/panel#tls), and set up renewal — `certbot renew` runs on a systemd timer by default. ## Using the certificate - **Panel** — set `webCertFile` (the full chain) and `webKeyFile` (the private key) in [Panel Settings](/docs/config/panel#tls). Both must be set for the panel to switch to HTTPS. Menu option **`11` — View Current Settings** prints the paths currently in use. - **Inbounds** — when you enable TLS on an inbound, reference the same certificate and key files (or paste their contents) in the inbound's TLS settings. See [Inbounds](/docs/config/inbounds) and [Transports](/docs/config/transports). Certificates expire (Let's Encrypt: 90 days; IP certs: ~6 days). The menu and Certbot both renew automatically, but the panel keeps reading the **files** at their fixed paths — so renew **in place** rather than moving the files, and the panel picks up the new cert on its next restart. **Force Renew** (menu `20`) triggers a renewal on demand. ## Next steps