shred / acme4j

Java client for ACME (Let's Encrypt)
https://acme4j.shredzone.org
Apache License 2.0
521 stars 96 forks source link

The challenge status was always "INVALID" #135

Closed fsl1994 closed 1 year ago

fsl1994 commented 1 year ago

Hello, I consulted you on gitlab last week, and I'm bothering you again. Hello, I consulted you on gitlab last week, and I'm bothering you again. I bought A domain name with A record configured. Then I tried to produce certificates. The challenge type was "HTTP", but the challenge status was always "INVALID", so the certificate could not be created. Can you help me see what the problem is.Looking forward to your reply. So the certificate could not be created. Can you help me to see what is wrong? Looking forward to your reply.

image

image

shred commented 1 year ago

The Order object also stores an error if it failed. Can you add a getError() to the log, e.g. like that?

                if (order.getStatus() == Status.INVALID) {
                    LOG.error("Order has failed, reason: {}", order.getError());
                    LOG.error(order.getError().toString());
                    throw new AcmeException("Order failed... Giving up.");
                }

It should then log the reason why the order is invalid.

fsl1994 commented 1 year ago

I didn't throw any exceptions during the authorization process. Line 437 is printed 10 times with the error message "status=INVALID, Challenge failed... Giving up." And then after authoriz(auth) is done, this method [order.execute(csrb.getEncoded())] should have an exception. The exception message is: "org. shredzone. acme4j. exception. AcmeServerException: Order 's status (" invalid") is not acceptable for finalization". So I can't print 264 lines, I can't print order.getError()

ilnW09ZAiK 7wJFk4J2im

shred commented 1 year ago

OK, it wasn't clear to me that the challenge is failing. Please change your code in line 436-439 like this:

if (status == Status.INVALID) {
    Debug.logInfo("authorize-domainName=%s, status=%s, Challenge failed... Giving up.", module, domain, status);
    Debug.logError("authorize-domainName=%s, reason=%s", module, domain, challenge.getError());
    throw new AcmeException("Challenge failed.. Giving up");
}

challenge.getError() will give you the reason for why your challenge has failed. That's in the example, too.

fsl1994 commented 1 year ago

I saw this challenge.getError : "status=INVALID, error=2a02:4780:3:696:0:aae:4af9:1: Invalid response from http://almanostore.com/.well-known/acme-challenge/qjUxh0eAfFpFAUrkfc8g4yxzw_q5bg_vYcftlXlac7M: 404, Challenge failed... Giving up."

I might know what went wrong. but I didn't know why it didn't work. Was it because I configured ipv6? eyGgB0q6Vb

shred commented 1 year ago

I don't think it's related to the IPv6 configuration.

The error means that Let's Encrypt has tried to access your HTTP challenge at http://almanostore.com/.well-known/acme-challenge/qjUxh0eAfFpFAUrkfc8g4yxzw_q5bg_vYcftlXlac7M, but got a 404 from your web server instead of the challenge response.

You should check that the response file is reachable from public. Is your web server configured properly to deliver the file? Also it must be available there before you invoke challenge.trigger(), and it must be there until the challenge is completed (either in VALID or INVALID state).

fsl1994 commented 1 year ago

However, my other test domain name is able to generate the certificate correctly, and path is accessible to the public network.

I access this path on the Internet and can download the file. http://almanostore.com/.well-known/acme-challenge/qjUxh0eAfFpFAUrkfc8g4yxzw_q5bg_vYcftlXlac7M

shred commented 1 year ago

Well, all I can tell you is that Let's Encrypt couldn't download the file, but got a 404.

A common problem is that challenge.trigger() is invoked too early. Let's Encrypt may access the file as soon as challenge.trigger() is invoked. If your web server is not ready yet (e.g. because the file has not been written yet, or needs to be replicated first), you will get this error.

fsl1994 commented 1 year ago

oh, can I make the thread wait a few seconds before calling challenge.trigger() ?Maybe can solve this problem?

shred commented 1 year ago

It depends on your implementation. But it's surely worth a try.

fsl1994 commented 1 year ago

I forgot to show you the code for the challenge. I wrote this file after the findChallenge() method. It should be okay, right?

HODJNf7H0O

shred commented 1 year ago

Generally it looks good to me.

On a side node: Your bufferedWriter is not closed. This is not the cause for the problem because you do a bufferedWriter.flush(). However you should prefer constructs like try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file))) { ... }, because it will auto-close your writer at the end of the try block. Also see here: https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html

fsl1994 commented 1 year ago

I'm sorry. I'm a little bad at it. Where should I call this method [challenge.trigger() ], and how should I change it? Can you teach me? hahaha

gcMY5Wm1y0

shred commented 1 year ago

What you can try out is a Thread.sleep(3000L) before challenge.trigger(). Anyway, the reason for the error is that Let's Encrypt was unable to access your challenge file. The problem is related with your server setup or your implementation, and is out of scope of this issue. Please understand that I don't have the time to debug that problem for you, but you should find everything you need in this issue.

I will close this ticket now, since the problem is not related to acme4j.