cURL error 60: SSL certificate problem: certificate has expired

Support intro

Sorry to hear you’re facing problems. :slightly_frowning_face:

The community help forum (help.nextcloud.com) is for home and non-enterprise users. Support is provided by other community members on a best effort / “as available” basis. All of those responding are volunteering their time to help you.

If you’re using Nextcloud in a business/critical setting, paid and SLA-based support services can be accessed via portal.nextcloud.com where Nextcloud engineers can help ensure your business keeps running smoothly.

Getting help

In order to help you as efficiently (and quickly!) as possible, please fill in as much of the below requested information as you can.

Before clicking submit: Please check if your query is already addressed via the following resources:

(Utilizing these existing resources is typically faster. It also helps reduce the load on our generous volunteers while elevating the signal to noise ratio of the forums otherwise arising from the same queries being posted repeatedly).

The Basics

  • Nextcloud Server version (e.g., 29.x.x):
    • 32.0.5
  • Operating system and version (e.g., Ubuntu 24.04):
    • Debian 13
  • Web server and version (e.g, Apache 2.4.25):
    • Nginx 1.26.3
  • PHP version (e.g, 8.3):
    • 8.4 ( was 8.3 before )
  • Is this the first time you’ve seen this error? (Yes / No):
    • yes
  • When did this problem seem to first start?
    • today after updating nextcloud
  • Installation method (e.g. AlO, NCP, Bare Metal/Archive, etc.)
    • manual archive
  • Are you using CloudfIare, mod_security, or similar? (Yes / No)
    • no

Summary of the issue you are facing:

Hello, after updating my nextcloud to version 32.0.5, I am suddenly unable to update any app or do any task connecting to outside sources at all. I continously get the curl error 60 with description “certificate has expired”. The thing is, the destination certificate has most certainly not expired ( github.com ). When I try running curl directly on the destination url ( https://github.com/nextcloud-releases/calendar/releases/download/v6.2.0/calendar-v6.2.0.tar.gz ) I get no error at all. When I tried to reproduce the error using a small php script ( see below ) it also finished without any problem. When trying to add debug output to nextcloud/guzzlehttp, I also was unable to get any informative output. I tried disabling the firewall, forcing curl to IPv4 ( as suggested by a similar issue #240104 ) updating the ca bundle in ressources/config/ca-bundle.crt, updating the system ca bundle, re-installing nextcloud etc etc etc. Nothing I tried worked.

<?php

$ch = curl_init("https://github.com/ONLYOFFICE/onlyoffice-nextcloud/releases/download/v9.12.0/onlyoffice.tar.gz");

//curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_CAINFO, "resources/config/ca-bundle.crt");
// resources/config/ca-bundle.crt
if(curl_exec($ch) === false) {

        var_dump(curl_error($ch));
} else {
//      var_dump(curl_getinfo($ch));
        echo "<pre>" . print_r(curl_version(), true) . "</pre>";
}

Steps to replicate it (hint: details matter!):

  1. Update to latest nextcloud

  2. Try installing any app

  3. Profit

( honestly I cannot tell you why this is happening. Only nextcloud seems to be affected by this, other web applications do not seem to face this issue, and I cannot reproduce it outside of nextcloud )

Log entries

Nextcloud

Please provide the log entries from your Nextcloud log that are generated during the time of problem (via the Copy raw option from Administration settings->Logging screen or from your nextcloud.log located in your data directory). Feel free to use a pastebin/gist service if necessary.

 {"reqId":"YjnJbLzU6hgAFZZXaN2b","level":3,"time":"2026-02-11T17:15:35+00:00","remoteAddr":"2a02:8071:5be0:ba10:1031:941b:5f37:4c7e","user":"#REMOVED FOR PRIVACY#","app":"settings","method":"POST","url":"/settings/apps/enable","scriptName":"/index.php","message":"could not enable apps","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:147.0) Gecko/20100101 Firefox/147.0","version":"32.0.5.0","exception":{"Exception":"GuzzleHttp\\Exception\\RequestException","Message":"cURL error 60: SSL certificate problem: certificate has expired (see https://curl.haxx.se/libcurl/c/libcurl-errors.html) for https://github.com/nextcloud-releases/calendar/releases/download/v6.2.0/calendar-v6.2.0.tar.gz","Code":0,"Trace":[{"file":"/var/www/clients/client1/web98/web/3rdparty/guzzlehttp/guzzle/src/Handler/CurlFactory.php","line":205,"function":"createRejection","class":"GuzzleHttp\\Handler\\CurlFactory","type":"::","args":["*** sensitive parameters replaced ***"]},{"file":"/var/www/clients/client1/web98/web/3rdparty/guzzlehttp/guzzle/src/Handler/CurlFactory.php","line":157,"function":"finishError","class":"GuzzleHttp\\Handler\\CurlFactory","type":"::"},{"file":"/var/www/clients/client1/web98/web/3rdparty/guzzlehttp/guzzle/src/Handler/CurlHandler.php","line":47,"function":"finish","class":"GuzzleHttp\\Handler\\CurlFactory","type":"::"},{"file":"/var/www/clients/client1/web98/web/3rdparty/guzzlehttp/guzzle/src/Middleware.php","line":142,"function":"__invoke","class":"GuzzleHttp\\Handler\\CurlHandler","type":"->"},{"file":"/var/www/clients/client1/web98/web/lib/private/Http/Client/DnsPinMiddleware.php","line":150,"function":"{closure:{closure:GuzzleHttp\\Middleware::tap():137}:138}","class":"GuzzleHttp\\Middleware","type":"::","args":["*** sensitive parameters replaced ***"]},{"file":"/var/www/clients/client1/web98/web/3rdparty/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php","line":35,"function":"{closure:{closure:OC\\Http\\Client\\DnsPinMiddleware::addDnsPinning():104}:105}","class":"OC\\Http\\Client\\DnsPinMiddleware","type":"->","args":["*** sensitive parameters replaced ***"]},{"file":"/var/www/clients/client1/web98/web/3rdparty/guzzlehttp/guzzle/src/Middleware.php","line":31,"function":"__invoke","class":"GuzzleHttp\\PrepareBodyMiddleware","type":"->"},{"file":"/var/www/clients/client1/web98/web/3rdparty/guzzlehttp/guzzle/src/RedirectMiddleware.php","line":71,"function":"{closure:{closure:GuzzleHttp\\Middleware::cookies():28}:29}","class":"GuzzleHttp\\Middleware","type":"::","args":["*** sensitive parameters replaced ***"]},{"file":"/var/www/clients/client1/web98/web/3rdparty/guzzlehttp/guzzle/src/Middleware.php","line":66,"function":"__invoke","class":"GuzzleHttp\\RedirectMiddleware","type":"->"},{"file":"/var/www/clients/client1/web98/web/3rdparty/guzzlehttp/guzzle/src/HandlerStack.php","line":75,"function":"{closure:{closure:GuzzleHttp\\Middleware::httpErrors():60}:61}","class":"GuzzleHttp\\Middleware","type":"::","args":["*** sensitive parameters replaced ***"]},{"file":"/var/www/clients/client1/web98/web/3rdparty/guzzlehttp/guzzle/src/Client.php","line":333,"function":"__invoke","class":"GuzzleHttp\\HandlerStack","type":"->"},{"file":"/var/www/clients/client1/web98/web/3rdparty/guzzlehttp/guzzle/src/Client.php","line":169,"function":"transfer","class":"GuzzleHttp\\Client","type":"->"},{"file":"/var/www/clients/client1/web98/web/3rdparty/guzzlehttp/guzzle/src/Client.php","line":189,"function":"requestAsync","class":"GuzzleHttp\\Client","type":"->","args":["*** sensitive parameters replaced ***"]},{"file":"/var/www/clients/client1/web98/web/lib/private/Http/Client/Client.php","line":206,"function":"request","class":"GuzzleHttp\\Client","type":"->"},{"file":"/var/www/clients/client1/web98/web/lib/private/Installer.php","line":238,"function":"get","class":"OC\\Http\\Client\\Client","type":"->","args":["*** sensitive parameters replaced ***"]},{"file":"/var/www/clients/client1/web98/web/apps/settings/lib/Controller/AppSettingsController.php","line":571,"function":"downloadApp","class":"OC\\Installer","type":"->"},{"file":"/var/www/clients/client1/web98/web/lib/private/AppFramework/Http/Dispatcher.php","line":204,"function":"enableApps","class":"OCA\\Settings\\Controller\\AppSettingsController","type":"->"},{"file":"/var/www/clients/client1/web98/web/lib/private/AppFramework/Http/Dispatcher.php","line":118,"function":"executeController","class":"OC\\AppFramework\\Http\\Dispatcher","type":"->"},{"file":"/var/www/clients/client1/web98/web/lib/private/AppFramework/App.php","line":153,"function":"dispatch","class":"OC\\AppFramework\\Http\\Dispatcher","type":"->"},{"file":"/var/www/clients/client1/web98/web/lib/private/Route/Router.php","line":321,"function":"main","class":"OC\\AppFramework\\App","type":"::"},{"file":"/var/www/clients/client1/web98/web/lib/base.php","line":1061,"function":"match","class":"OC\\Route\\Router","type":"->"},{"file":"/var/www/clients/client1/web98/web/index.php","line":25,"function":"handleRequest","class":"OC","type":"::"}],"File":"/var/www/clients/client1/web98/web/3rdparty/guzzlehttp/guzzle/src/Handler/CurlFactory.php","Line":276,"message":"could not enable apps","exception":[],"CustomMessage":"could not enable apps"},"id":"698cbcbd0df9c"}

Configuration

Nextcloud

The output of occ config:list system or similar is best, but, if not possible, the contents of your config.php file from /path/to/nextcloud is fine (make sure to remove any identifiable information!):

{
    "system": {
        "instanceid": "***REMOVED SENSITIVE VALUE***",
        "passwordsalt": "***REMOVED SENSITIVE VALUE***",
        "secret": "***REMOVED SENSITIVE VALUE***",
        "trusted_domains": [
            "#REMOVED FOR PRIVACY#",
            "127.0.0.1",
            "#REMOVED FOR PRIVACY#"
        ],
        "datadirectory": "***REMOVED SENSITIVE VALUE***",
        "dbtype": "mysql",
        "version": "32.0.5.0",
        "overwrite.cli.url": "#REMOVED FOR PRIVACY#",
        "dbname": "***REMOVED SENSITIVE VALUE***",
        "dbhost": "***REMOVED SENSITIVE VALUE***",
        "dbport": "",
        "dbtableprefix": "oc_",
        "dbuser": "***REMOVED SENSITIVE VALUE***",
        "dbpassword": "***REMOVED SENSITIVE VALUE***",
        "installed": true,
        "memcache.local": "\\OC\\Memcache\\Redis",
        "memcache.distributed": "\\OC\\Memcache\\Redis",
        "memcache.locking": "\\OC\\Memcache\\Redis",
        "redis": {
            "host": "***REMOVED SENSITIVE VALUE***",
            "port": 6379,
            "dbindex": 5
        },
        "mail_smtpmode": "smtp",
        "mail_smtpauthtype": "LOGIN",
        "mail_sendmailmode": "smtp",
        "mail_smtpauth": 1,
        "mail_from_address": "***REMOVED SENSITIVE VALUE***",
        "mail_domain": "***REMOVED SENSITIVE VALUE***",
        "mail_smtphost": "***REMOVED SENSITIVE VALUE***",
        "mail_smtpname": "***REMOVED SENSITIVE VALUE***",
        "mail_smtppassword": "***REMOVED SENSITIVE VALUE***",
        "maintenance": false,
        "theme": "",
        "loglevel": 0,
        "csrf.optout": [
            "\/^WebDAVFS\/",
            "\/^Microsoft-WebDAV-MiniRedir\/",
            "\/KeeWeb\\\/\\d[.]\\d[.]\\d\/",
            "\/KeeWeb\\\/\\d+\\.\\d+\\.\\d+\/"
        ],
        "app_install_overwrite": [
            "keeweb",
            "twofactor_gateway"
        ],
        "default_phone_region": "DE",
        "mysql.utf8mb4": true,
        "updater.release.channel": "stable",
        "ncd_admin_settings": {
            "disallow_aria2_settings": "1"
        },
        "mail_smtpsecure": "ssl",
        "mail_smtpport": "465",
        "enable_previews": true,
        "preview_concurrency_new": 8,
        "enabledPreviewProviders": [
            "OC\\Preview\\Movie",
            "OC\\Preview\\PNG",
            "OC\\Preview\\JPEG",
            "OC\\Preview\\GIF",
            "OC\\Preview\\BMP",
            "OC\\Preview\\XBitmap",
            "OC\\Preview\\MP3",
            "OC\\Preview\\MP4",
            "OC\\Preview\\TXT",
            "OC\\Preview\\MarkDown",
            "OC\\Preview\\PDF",
            "OC\\Preview\\MOV"
        ],
        "apps_paths": [
            {
                "path": "\/var\/www\/clients\/client1\/web98\/web\/apps\/",
                "url": "\/apps",
                "writable": true
            }
        ],
        "maintenance_window_start": 1,
        "updater.secret": "***REMOVED SENSITIVE VALUE***"
    }
}

Apps

The output of occ app:list (if possible).

Enabled:
  - activity: 5.0.0-dev.0
  - bruteforcesettings: 5.0.0-dev.0
  - circles: 32.0.0
  - cloud_federation_api: 1.16.0
  - comments: 1.22.0
  - contactsinteraction: 1.13.1
  - dav: 1.34.2
  - federatedfilesharing: 1.22.0
  - federation: 1.22.0
  - files: 2.4.0
  - files_downloadlimit: 5.0.0-dev.0
  - files_pdfviewer: 5.0.0-dev.0
  - files_reminders: 1.5.0
  - files_sharing: 1.24.1
  - files_trashbin: 1.22.0
  - files_versions: 1.25.0
  - logreader: 5.0.0-dev.0
  - lookup_server_connector: 1.20.0
  - nextcloud_announcements: 4.0.0-dev.0
  - notifications: 5.0.0-dev.0
  - oauth2: 1.20.0
  - password_policy: 4.0.0-dev.0
  - photos: 5.0.0-dev.1
  - privacy: 4.0.0-dev.0
  - profile: 1.1.0
  - provisioning_api: 1.22.0
  - recommendations: 5.0.0-dev.0
  - related_resources: 3.0.0-dev.0
  - serverinfo: 4.0.0-dev.0
  - settings: 1.15.1
  - systemtags: 1.22.0
  - text: 6.0.1
  - theming: 2.7.0
  - twofactor_backupcodes: 1.21.0
  - twofactor_nextcloud_notification: 6.0.0-dev.0
  - twofactor_totp: 14.0.0
  - updatenotification: 1.22.0
  - viewer: 5.0.0-dev.0
  - webhook_listeners: 1.3.0
  - workflowengine: 2.14.0
Disabled:
  - admin_audit: 1.22.0
  - app_api: 32.0.0 (installed 32.0.0)
  - dashboard: 7.12.0 (installed 7.7.0)
  - encryption: 2.20.0
  - files_external: 1.24.1
  - firstrunwizard: 5.0.0-dev.0 (installed 2.17.0)
  - sharebymail: 1.22.0 (installed 1.18.0)
  - support: 4.0.0-dev.0 (installed 1.11.1)
  - survey_client: 4.0.0-dev.0 (installed 1.14.0)
  - suspicious_login: 10.0.0-dev.0
  - user_ldap: 1.23.0
  - user_status: 1.12.0 (installed 1.8.1)
  - weather_status: 1.12.0 (installed 1.8.0)

I did in fact disable IP6 from my server completely and then my downloads worked. My provider is OVH - maybe yours is the same. The orders below allowed me to determine the expired certificate:

HOST=release-assets.githubusercontent.com # replace with the one you see
openssl s_client -connect $HOST:443 -servername $HOST </dev/null 2>/dev/null
| openssl x509 -noout -subject -issuer -dates

Hope this helps

Thank you very much for your reply. I actually did try that, and it still worked without issue. I was losing my mind over this, but you pointed me in the right direction because I found it.

  1. release-assets.githubusercontent.com does not have an AAAA record. It only has an A record.
  2. My server is part of a domain, so a search domain is setup in the system’s resolv.conf.

Now the funny bit: apparently the search domain setting was causing all domains to resolve back against my own server because of a wildcard entry. So instead of looking up release-assets.githubusercontent.com and failing because there is no AAAA record, it would append this domain to my own (e.g., release-assets.githubusercontent.com.example.com), and the wildcard record would be returned and cause curl to actually connect to my own server. And because my server’s SSL cert is not valid for release-assets.githubusercontent.com, I would get an expired certificate error.

So the only fix I had to apply was removing this line from my resolv.conf file:
search example.com

This topic was automatically closed 8 days after the last reply. New replies are no longer allowed.