Please fill out the fields below so we can help you better. Note: you must provide your domain name to get help. Domain names for issued certificates are all made public in Certificate Transparency logs (e.g. crt.sh | example.com), so withholding your domain name here does not increase secrecy, but only makes it harder for us to provide help.
My domain is:
yfu.one www.yfu.one
I have my webserver running on a digitalocean droplet on port 443. I want to redirect port 80 to port 443 so that when a user types my domain name yfu.one in the address bar, the default http connection redirects to an https connection to port 443. But this creates an issue when renewing certbot, which expects to communicate on port 80.
Is there a way to add a conditional check to see if the request is coming from certbot, in which case the "return 404 # managed by certbot" is triggered? Or is there a better way of redirecting port 80?
My configuration is
#/etc/nginx/sites-available/default
server {
root /var/www/example.com/html;
index index.html index.htm index.nginx-debian.html;
server_name yfu.one www.yfu.one;
location / {
try_files $uri $uri/ =404;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/yfu.one/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/yfu.one/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = www.yfu.one) {
return 301 https://$host$request_uri;
} # managed by Certbot
if ($host = yfu.one) {
return 301 https://$host$request_uri;
} # managed by Certbot
server_name yfu.one www.yfu.one;
listen 80;
#return 404; # managed by Certbot, now commented out
return 301 https://yfu.one$request_uri; # redirect port 80 to https port
}
I'm using a control panel to manage my site (no, or provide the name and version of the control panel):
no control panel, using ssh
The version of my client is (e.g. output of certbot --version or certbot-auto --version if you're using Certbot): certbot 1.29.0
Let's Encrypt follows redirects from HTTP to HTTPS, so I don't really see the issue here, could you explain why you think it's an issue more?
Edit:
Ah, I see you're running something called "uvicorn" on port 443 instead of nginx.
Well, you could just put the redirects on the port 80 server block between a location section excluding the /.well-known/acme-challenge/ path. I myself am not an nginx user, so I personally wouldn't know the syntax for that.
Also, which plugin was used by Certbot? The nginx plugin or the webroot plugin?
Your server block for port 80 could look something like below.
server {
if ($host = www.yfu.one) {
return 301 https://$host$request_uri;
} # managed by Certbot
if ($host = yfu.one) {
return 301 https://$host$request_uri;
} # managed by Certbot
server_name yfu.one www.yfu.one;
listen 80;
# NEW LINES
# ACME Challenge from Let's Encrypt Server
# (set root folder as needed)
location /.well-known/acme-challenge/ {
root /var/www/example.com/html;
}
# All other requests
location / {
#return 404; # managed by Certbot, now commented out
return 301 https://yfu.one$request_uri; # redirect port 80 to https port
}
}
Thanks for the help, though it looks like I still need to stop nginx to renew successfully. I copied in the config, restarted nginx and then ran certbot renew --dry-run, which gave me an error due to web server running on port 80 (besides nginx I just have uvicorn/fastapi running on port 443). If I shut down nginx, certbot renew --dry-run completes successfully
I will probably end up just using the hacky approach of scheduling my own task to shut down nginx, run certbot renew, then restart nginx.
Thanks for taking the time to write up the config, appreciate it!
Yes! I am running uvicorn based fastapi (with mounted gradio apps for frontend) on port 443.
I'm not completely sure which certbot plugin I have, I originally installed certbot following the instructions at Certbot Instructions | Certbot, running sudo certbot certonly --standalone
All this web hosting stuff is new to me, in fact I originally tried to redirect port 80 to 443 by messing with iptables, then I ran iptables -F thinking it would reset my config (I immediately lost access my original droplet and later destroyed it)
Do you need nginx for some other reason? Because it sounds like you have a webserver for port 443 (HTTPS) and just need the certs. The standalone is fine for that.
I need nginx for the port redirect from 80 to 443 (typing in yfu.one in the address bar defaults to http://yfu.one, which is a connection error if I do not have nginx running)
But maybe that is the issue: that I'm using the standalone authenticator? I will try reinstalling certbot with sudo certbot certonly --webroot
OK. But, why do you have a server block in nginx for port 443 when it is being handled by your other webserver?
If you want to just use nginx to redirect port 80 to your other webserver 443, then we need to switch you off --standalone and use a different method (certonly --nginx is another option)
I mistakenly thought that if I installed certbot together with nginx, nginx could handle my redirect and the certbot challenge as well. Thanks again for the pointers, they were very helpful!
After sorting this out, here's what I have:
Like you said I only needed the server block to handle the redirect from 80 to https
# /etc/nginx/sites-available/default
server {
server_name yfu.one www.yfu.one;
listen 80;
return 301 https://yfu.one$request_uri; # redirect port 80 to https port
}
I converted the renewal config file to webroot mode
# /etc/letsencrypt/renewal/yfu.one.conf
# renew_before_expiry = 30 days
version = 2.5.0
archive_dir = /etc/letsencrypt/archive/yfu.one
cert = /etc/letsencrypt/live/yfu.one/cert.pem
privkey = /etc/letsencrypt/live/yfu.one/privkey.pem
chain = /etc/letsencrypt/live/yfu.one/chain.pem
fullchain = /etc/letsencrypt/live/yfu.one/fullchain.pem
# Options used in the renewal process
# converted from standalone config -> webroot config
[renewalparams]
account = 8498ef31eb62119e030cb6175cf4b123
authenticator = webroot # change from "standalone" to "webroot"
server = https://acme-v02.api.letsencrypt.org/directory
key_type = ecdsa
[[webroot_map]] # added
# webroot path for each domain should point to folder mounted as static files at fastapi index route "/"
yfu.one = /root/yfuone/frontend/certbot_webroot # added
www.yfu.one = /root/yfuone/frontend/certbot_webroot # added
Then I added a route into the fastapi app to handle the challenge
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse
from pathlib import Path
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Hello World"}
WEBROOT_PATH = "/root/yfuone/frontend/certbot_webroot" # same as webroot in yfu.one.conf
# mounting static files at index route caused site to malfunction
#app.mount("/", StaticFiles(directory=WEBROOT_PATH))
# add route to handle cerbot challenge
@app.get("/.well-known/acme-challenge/{filename}")
async def acme_challenge(filename: str):
certbot_file = Path(f"{WEBROOT_PATH}/.well-known/acme-challenge/{filename}")
if certbot_file.is_file():
return FileResponse(certbot_file)
else:
print(f"Cannot find certbot challenge file {certbot_file}")
After installing certificates with sudo certbot certonly --standalone, running sudo certbot certonly --webroot errored out saying I had a web server running on port 80, and the renewal config file was not changed. To get it to run correctly, I had to delete the renewal config file as well as move (or delete) the certificate files in /etc/letsencrypt/live/