Certificate created at installation has expired

And now I can’t use https to get to the GUI.

I’m not using any of the DNS services listed in ACME authenticators.

I notice that the old capability to create my own certificate authority, and hence my own certificates, has disappeared.

This is a personal-use server. Neither I nor anybody else will be relying on the certificate to validate that the server is really mine (I can see it on the rack across the room! I don’t need public-key certainty). But I DO want my http connections to it to be encrypted. What’s the easiest way to do this? If I create a new certificate manually (I’ve done it before, I could probably dig up how to do it again) is there some straight-forward way to import it and use it?

Sure. Go to Credentials → Certificates and click the Import button on the Certificates pane:

Enter a name, paste in the cert and key, click Import again:

If you’re going to need to do this on some kind of regular basis, look into my script or @jjrushford 's tnascert-deploy.

I can import certificates I generate, and they appear in the list in the gui. But when I go to system → general → GUI SSL certificate, they don’t appear on the list that I can select from. (Even after rebooting.) They do still appear on the list on the credentials page.

I’m assuming somehow the certificate doesn’t have the right magic incantations in it, but it’s not giving me any errors, it just fails to appear on the list of certificates to use. Any clues?

You’re providing the private key as well, right?

Yes, and the private key password (in the CA2 version; I tried both, unencrypted private key, then encrypted, same results both times).

The certificate is being created as:

$ openssl req -x509 -new  -key ddbCA2.key -sha256 -days 3650 -out fsfs2.crt -subj "/CN=fsfs.bpoly.local" -addext "subjectAltName=DNS:fsfs.bpoly.local,DNS:fsfs.local,IP:19
2.168.1.205"

I really don’t know. I wonder, though, if the duration of the cert might be the issue? The maximum allowed for a public CA is just over a year, and the default cert is now created for about the same length of time.

Can you try using either my script or tnascert-deploy to import the script? My thought/hope with this is that it might produce an error pointing to why you can’t choose the cert in the GUI.

I’m in the mode of trying things just now, sure.

I’ll cut back the duration on my own, see if that helps, and if that doesn’t work I’ll try one of the scripts you recommend and see if anything interesting happens.

Cutting back the duration didn’t help. Next up, trying your script.

Well, this might be information:

ddb@fsfs:~/proj/deploy-freenas$ ./deploy_truenas.py
Enter PEM pass phrase:
2026-05-17 23:09:33,488 - root - INFO - ✅ Certificate and private key match.
2026-05-17 23:09:33,498 - websocket - INFO - Websocket connected
2026-05-17 23:09:34,207 - root - CRITICAL - Certificate import failed: [EINVAL] certificate_create.privatekey: A valid private key is required, with a passphrase if one has been set.

The private key was generated with:

openssl genrsa  -des3 -out ddbCA2.key 4096

Which doesn’t seem particularly doubtful.

Reading between the lines, it seems to say that the private key and certificate were verified to match, but then importing the certificate failed because of something to do with the private key?

You probably need a key without a pass phrase.

My script doesn’t have any logic to deal with encrypted private keys. Can you try with an unencrypted private key?

Sure. That’s where I started, but the GUI for importing a certificate doesn’t seem to have an option for unencrypted private keys (except just leaving the box empty; is what to do if importing manually?).

I’ll try an unencrypted private key with your script, anyway.

This might, again, constitute information :slight_smile: .

ddb@fsfs:~/proj/deploy-freenas$ ./deploy_truenas.py
2026-05-18 10:38:14,327 - root - INFO - ✅ Certificate and private key match.
2026-05-18 10:38:14,336 - websocket - INFO - Websocket connected
2026-05-18 10:38:20,767 - root - INFO - Certificate letsencrypt-2026-05-18-103813 imported.
2026-05-18 10:38:25,303 - root - ERROR - Failed to update UI certificate: [EINVAL] general_settings.ui_certificate: Selected certificate must be a valid certificate and not a CSR or CA
2026-05-18 10:38:25,303 - root - INFO - Not setting FTP cert because ftp_enabled is false.
2026-05-18 10:38:25,303 - root - INFO - Not setting app certificates because apps_enabled is false.
2026-05-18 10:38:25,303 - root - INFO - Not deleting old certs because delete_old_certs is false.
2026-05-18 10:38:25,305 - root - INFO - Restarting web UI.
2026-05-18 10:38:25,306 - root - INFO - deploy_truenas finished.

And the certificate now shows in the Credentials page of the GUI, confirming the “certificate imported” message. (Yeah, eventually I’ll change the name in the deploy_config file to avoid casting aspersions on letsencrypt.)

So, it’s invalid, or a CA, or a CSR?

After generating the certificate, I went through the validation steps given in Creating a Self-Signed SSL Certificate: A Comprehensive Guide — linuxvox.com and it seemed to think I’d generated valid stuff. Is there another source that’s better? Or do you have an example of commands that create a CA and cert that will work? (Or…could it be somehow specific to the name and secondary name I’ve put on mine?)

(I think everything in this next dump is safe; but if not, the cert isn’t in use anywhere and won’t be for more than moments, it’ll be some new cert that’s actually put to use later.)

Output from openssl x509 -in fsfs.crt -text -noout

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            22:c2:4f:64:19:3f:16:ad:bd:4d:d1:ce:ba:0f:22:b3:06:57:93:b6
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN = localhost
        Validity
            Not Before: May 17 18:07:48 2026 GMT
            Not After : May 14 18:07:48 2036 GMT
        Subject: CN = localhost
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (4096 bit)
                Modulus:
                    00:be:99:56:5e:1d:ba:5a:a5:c2:01:34:c7:e1:b0:
                    0f:cb:30:ab:82:93:c8:3b:3d:5c:eb:f3:5c:b3:6f:
                    71:44:9a:97:14:0a:ed:40:13:cf:b2:16:f3:3b:8c:
                    6c:4f:5f:69:ac:16:a4:1b:d4:2f:c0:01:da:bc:14:
                    87:84:29:d4:3c:8f:d5:e7:5a:98:1a:56:11:bb:3d:
                    3c:86:4a:c6:c2:06:6b:bc:98:f0:40:3c:ae:8f:e6:
                    6f:4d:1e:a1:6a:d4:93:50:9a:14:d8:30:c4:d9:ce:
                    c3:e2:f9:58:80:1c:f5:32:be:c4:bb:d1:bb:a6:82:
                    74:58:20:2d:5e:45:4f:33:6b:c5:66:f0:86:c0:ef:
                    3f:19:74:fa:df:89:3f:fd:b4:18:4a:32:8b:29:22:
                    ff:43:fc:42:32:a2:d1:9a:63:1f:fe:8d:19:f8:c9:
                    f4:2a:09:04:af:9a:d6:f4:7b:42:03:36:2c:db:6f:
                    36:e4:5f:14:9f:28:5c:29:42:7e:4a:8f:68:e7:1a:
                    c3:17:8d:9e:2d:e6:1e:09:44:a5:4c:34:8a:94:e7:
                    30:b5:30:ae:42:d6:18:3e:2e:46:12:e7:5e:c8:2d:
                    b4:98:3c:d4:b9:cc:3a:be:b8:c3:0f:65:65:4a:be:
                    c0:8b:fb:4f:f4:bb:54:42:50:c6:bf:f2:e8:4f:12:
                    38:e0:74:d4:40:6e:b2:ba:77:14:6c:ec:d7:c3:8d:
                    1e:b3:5f:06:c2:3e:c7:92:04:fb:a7:f2:80:89:5f:
                    86:74:fa:a7:d4:e9:9f:68:1c:80:22:68:af:cb:d7:
                    8a:6a:7a:7a:40:35:42:06:65:c2:4a:cd:80:bf:9c:
                    7f:10:75:45:66:bb:e3:90:0d:06:f1:d9:c7:55:46:
                    d9:15:e6:0f:90:0a:24:1b:15:f2:82:c5:87:94:61:
                    15:b6:a6:42:5e:d5:d9:bc:4f:41:ef:93:56:52:71:
                    66:57:04:59:ad:4a:10:8d:56:06:1e:70:b7:ec:9c:
                    81:74:db:cd:de:05:01:4b:4b:95:4e:f9:f7:3d:62:
                    50:ad:28:2f:22:7a:fc:fe:8a:56:c3:87:d5:11:56:
                    d0:47:4a:df:4c:1b:9e:5a:b7:5d:2f:d0:a3:3f:0d:
                    ef:b5:b9:04:a5:c1:67:6f:8e:40:07:fd:20:e2:d4:
                    cf:dc:14:46:f2:ea:a0:ae:0f:d8:f4:67:e3:fd:04:
                    63:3a:73:f3:32:07:59:0f:86:f5:ac:b2:29:b3:91:
                    d7:69:47:a2:68:05:5a:c6:e0:f6:d3:4c:e5:38:89:
                    d0:2f:18:c2:7f:49:7e:2e:b6:65:fb:95:b4:83:b3:
                    9b:8b:23:c6:14:cd:27:a3:2f:3b:4a:dc:af:b0:e9:
                    3c:99:41
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Key Identifier: 
                17:47:2F:4D:80:F8:E9:BB:8E:CC:65:18:FC:A9:20:29:A6:57:C4:B3
            X509v3 Authority Key Identifier: 
                17:47:2F:4D:80:F8:E9:BB:8E:CC:65:18:FC:A9:20:29:A6:57:C4:B3
            X509v3 Basic Constraints: critical
                CA:TRUE
            X509v3 Subject Alternative Name: 
                DNS:localhost, DNS:fsfs.local, IP Address:192.168.1.205
    Signature Algorithm: sha256WithRSAEncryption
    Signature Value:
        4d:b3:dc:3b:ed:1f:c6:bb:71:36:5f:1d:3c:ca:81:da:0d:85:
        87:01:89:af:3f:4d:0b:bb:e6:fa:c6:46:75:d2:3a:69:66:e2:
        a2:cb:66:bb:6e:75:b1:fa:87:c7:24:4a:17:30:48:75:99:fe:
        91:7f:e7:cd:11:e6:25:b9:f7:de:fe:bd:d5:22:27:cd:15:00:
        82:d8:a8:93:b4:37:68:75:2d:7c:4d:00:5e:06:69:6d:4c:b1:
        a3:e5:05:d7:be:6f:fd:79:f8:8b:81:4a:39:72:29:3d:ad:8d:
        95:76:f1:ae:90:c9:91:07:51:03:9a:24:0a:f6:0b:db:db:1e:
        25:30:b6:f8:8b:e8:2d:c4:58:0e:bc:33:1d:bd:3d:d3:0b:43:
        c8:48:b3:e7:51:27:cf:52:f9:37:91:c2:94:7e:ef:9c:10:ee:
        1e:2d:34:8a:87:7c:fc:22:9f:f6:3b:a6:4b:08:5e:a7:47:32:
        2a:c7:f7:19:b9:5c:62:95:92:2a:47:cd:10:c6:5a:d9:22:89:
        a4:d2:88:8b:59:52:d4:6d:10:79:66:73:9e:9f:47:f0:9a:7f:
        93:b3:7f:31:bc:cb:d9:2e:51:5b:57:ab:b8:51:a5:1f:2d:67:
        63:b9:1b:a2:92:51:91:2c:18:87:50:da:1d:44:e6:fe:07:c6:
        69:cb:41:00:63:14:53:51:cb:b7:e1:0f:48:fd:06:81:1b:6b:
        ff:c4:6f:3b:6a:2c:76:06:94:a8:10:9a:b5:25:34:cb:ab:07:
        53:67:ef:88:f7:21:c3:2f:70:ff:52:d0:4b:1c:b7:47:ad:6f:
        5f:7d:0c:45:4c:cb:fd:ec:1d:2a:24:e5:e6:10:b2:db:e5:bf:
        98:23:8b:fc:cc:b0:4a:40:46:52:9e:5f:19:ee:15:e7:ef:a4:
        50:be:3e:c5:eb:69:f4:09:52:6a:93:27:61:ee:df:f6:49:af:
        dc:03:1e:e5:47:14:30:ca:ad:d0:f3:4e:ca:3f:ce:58:1b:0f:
        cf:20:f2:72:49:03:81:ce:c2:3a:93:6e:fe:e5:87:24:f5:b4:
        f5:4a:d3:af:aa:e2:c7:1e:61:dd:f9:a0:eb:e3:9c:66:78:cd:
        7e:09:0d:ac:83:f4:0a:35:69:e6:97:89:cb:82:b1:6e:52:00:
        33:ac:10:75:55:af:06:dd:df:54:72:d6:8a:f5:b5:7f:14:9b:
        8e:00:11:f7:ff:f0:1b:3a:82:f6:9f:e8:16:05:12:88:aa:f3:
        5c:6e:f2:66:6e:e4:89:1d:96:1c:e4:08:ae:ef:e8:d1:be:f9:
        de:4c:02:60:87:7e:69:d7:a5:a9:34:09:f9:e8:91:cc:f8:a5:
        bf:79:1f:52:e2:cc:91:57

“leaving the box empty” is the option for unencrypted private keys.

Well; maybe got something (certificate imported, appeared in the list for the GUI, let me select it for the GUI; GUI restart happening while I type).

Totally bizarro sequence though.

Created a new key and CA, seemed to be same params, but just following a different cookbook step by step.

Created a CSR, then created a certificate. I’m wondering if the key difference is the CN and SANs, note slight differences from what I posted earlier.

For the record, the config file I used to create the csr is:

[ req ]
distinguished_name = req_distinguished_name
req_extensions = v3_req
prompt = no

[ req_distinguished_name ]
C = US
ST = Minnesota
L = Minneapolis
O = Blaisdell Poly
OU = IT
CN = fsfs.local

[ v3_req ]
subjectAltName = @alt_names

[ alt_names ]
DNS.1 = fsfs.local
DNS.2 = fsfs
IP.1  = 192.168.1.205

Packaged the two together into a PEM file. (Tried uploading the two independently first. That errored out, same “failed but no information” message.) When I pasted the PEM file in as a certificate, it appeared in the list for GUI certs, but when I selected it, I got an error saying there was no private key.

So then I tried something bonkers, and pasted in the PEM file as the certificate, and then also pasted in the private key separately (no password, left that field empty). That also imported okay, and also appeared in the list of certificates for the GUI – and when I selected it it LET ME! Then it has to restart the GUI, and that’s where I am this moment. YES! It worked, I can now connect via https (had to tell firefox to trust this new self-signed certificate, no surprise there).

But yikes. There are clearly bugs here! (I’m running TrueNAS SCALE 25.10.3.1.) I’ve got a key and cert that work, which is good, but the obvious way to install them doesn’t work, and fails very uninformitavely.

I guess I have to try to file a ticket with enough information to reproduce the problem.

Dunno if it’s a good enough bug report, but Jira

Hi, the problem here is the flag basicConstraints = CA:TRUE. If you want to use your own certificate you must switch CA:TRUE to CA:FALSE with extensions like this (example from my setup):

  1. Create CA
openssl req -x509 -newkey rsa:2048 \
  -keyout webui-ca.key \
  -out webui-ca.crt \
  -sha256 -days 3650 -nodes \
  -subj "/C=FR/ST=Nord/L=Lille/O=Enterprise/CN=Enterprise-CA"
  1. Private key
openssl genrsa -out webui.key 2048
  1. CSR
openssl req -new -key webui.key -out webui.csr \

  -subj "/C=FR/ST=Nord/L=Lille/O=Enterprise/CN=192.168.99.52"
  1. Extensions
cat > webui.ext << EOF
basicConstraints = CA:FALSE
subjectAltName = IP:192.168.99.52,DNS:localhost
extendedKeyUsage = serverAuth
EOF
  1. Sign
openssl x509 -req -days 3650 \
-in webui.csr \
-CA webui-ca.crt \
-CAkey webui-ca.key \
-CAcreateserial \
-out webui.crt \
-sha256 \
-extfile webui.ext

Then import both webui.crt and webui.key in TrueNAS under System > Certificates > Add, using type Import Certificate.

Hope it helps

Aurélien

At the very least, your example points me at a lot of details to examine more carefully.

Since I was able to import and use the certificate I created, in the end, I don’t think it can really be of the wrong type?

But understanding the toolset better is always good (though I deal with this so rarely, I’ll probably have forgotten it all by the next time it comes up).

Edited to add:

A new cert built on your model imports in the expected way, rather than requiring the weird hack. It was accepted when I selected it to be the GUI cert on the NAS, waiting on restart to see if it works.

And edited again to say that, in fact, the certificate based on your procedure is working, and did import in the simple obvious way with no weird hacks needed. I may also have some clues what other things were wrong with my original procedure.

I do still think the error messages could have been more informative!

But it hasn’t been the same certificate throughout, has it? I thought in your last post you’d made a new one. And if you made a new cert “following a different cookbook,” it’s entirely possible (and I’d say probable) that it didn’t have that CA: True constraint on it.

The “easy button” here is to just subscribe to TrueNAS Connect. That will, among other things, automatically provision and renew a trusted TLS cert for your server, and I suspect that’s what iX really wants you to do. It’s free (for now, anyway) for the basic tier, which covers up to two servers, though with pretty minimal features.

Less easy, but still pretty easy, is to buy a domain, host its DNS with Cloudflare, and set up the cert through the GUI. iX have made that process inexcusably Byzantine (see Let's Encrypt Certificate for TrueNAS SCALE | Dan's Wiki), but you only have to do it once. Cost is around $10/yr (though can be more depending on your TLD).

Self-signed certs these days really are just a path to sadness.

Correct that there were 2 basically different certificates I have tried things with. (A 3rd one today, working with MDVAurelien’s suggestion.)

The “for now, anyway” is a red flag for me, and the limit of 2 is relevant, and it doesn’t automate the other case I need to use a better certificate for (the https gui connect for the household router). (Being right at the limit on day one is never good.)

But I’m also kind of stubborn, and old-school; I started running this series of servers in I think 1994, registered my first 3 domain names (only one of which I still own, though a second is in use for the non-profit I got it for, just now owned by them) before it cost money. (Originally co-located at a local ISP that I was also news admin for.)

The only person who connects to this server’s management port is me (at least the only person who is supposed to). Many, at least, of the issues with self-signed certificates apply when more people get involved. I just want that http connection to be encrypted.