I'm trying to find simple documentation on running certbot in a docker-container, but all I can find is complicated guides w/ running certbot + webserver etc. The official page is kinda useless... https://hub.docker.com/r/certbot/certbot/ .I already have webserver separate from my websites and I want to run certbot on it's own as well.
Can anybody give me some guidance on how I could generate certificates for mysite.com with a webroot of /opt/mysite/html.
As I already have services on port 443 and 80 I was thinking of using the "host-network" if needed for certbot, but I don't really understand why it needs access to 443 when my website is served over 443 already.
I have found something like so to generate a certbot container, but I have no idea how to "use it" or tell it to generate a cert for my site.
Eg:
WD=/opt/certbot
mkdir -p $WD/{mnt,setup,conf,www}
cd $WD/setup
cat << 'EOF' >docker-compose.yaml
version: '3.7'
services:
certbot:
image: certbot/certbot
volumes:
- type: bind
source: /opt/certbot/conf
target: /etc/letsencrypt
- type: bind
source: /opt/certbot/www
target: /var/www/certbot
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
EOF
chmod +x docker-compose.yaml
This link has something close to what I need, (obviously somehow I need to give it my domain as an argument!)
Letsencrypt + Docker + Nginx
docker run -it --rm \
-v certs:/etc/letsencrypt \
-v certs-data:/data/letsencrypt \
deliverous/certbot \
certonly \
--webroot --webroot-path=/data/letsencrypt \
-d api.mydomain.com
I like to keep everything pretty "isolated" so I'm looking to just have certbot run in it's own container and configure nginx/webserver to use the certs seperatley and not have certbot either autoconfigure nginx or run in the same stack as a webserver.
Well I have been learing a lot about docker recently and i recently learned how to look at the Dockerfile. The certbot dockerfile gave me some more hints.
Basically you can append the follow to your docker-compose.yaml and it is as if appending to certbot on the CLI. I will update with my working configs, but I was blocked due to the "Rate Limit of 5 failed auths/hour" :(
See Entrypoint of DockerFile
ENTRYPOINT [ "certbot" ]
Docker-Compose.yaml:
command: certonly --webroot -w /var/www/html -d www.examplecom -d examplecom --non-interactive --agree-tos -m example#example.com
I will update with my full config once I get it working and will be including variables to utilize .env file.
Full Config Example:
WD=/opt/certbot
mkdir -p $WD/{setup,certbot_logs}
cd $WD/setup
cat << 'EOF' >docker-compose.yaml
version: '3.7'
services:
certbot:
container_name: certbot
hostname: certbot
image: certbot/certbot
volumes:
- type: bind
source: /opt/certbot/certbot_logs
target: /var/log/letsencrypt
- type: bind
source: /opt/nginx/ssl
target: /etc/letsencrypt
- type: bind
source: ${WEBROOT}
target: /var/www/html/
environment:
- 'TZ=${TZ}'
command: certonly --webroot -w /var/www/html -d ${DOMAIN} -d www.${DOMAIN} --non-interactive --agree-tos --register-unsafely-without-email ${STAGING}
EOF
chmod +x docker-compose.yaml
cd $WD/setup
Variables:
cat << 'EOF'>.env
WEBROOT=/opt/example/example_html
DOMAIN=example.com
STAGING=--staging
TZ=America/Whitehorse
EOF
chmod +x .env
NGinx:
server {
listen 80;
listen [::]:80;
server_name www.example.com example.com;
location /.well-known/acme-challenge/ {
proxy_pass http://localhost:8575/$request_uri;
include /etc/nginx/conf.d/proxy.conf;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
listen [::]:443;
server_name www.example.com example.com;
# ssl_certificate /etc/ssl/live/example.com/fullchain.pem;
# ssl_certificate_key /etc/ssl/live/example.com/privkey.pem;
ssl_certificate /etc/ssl/fake/fake.crt;
ssl_certificate_key /etc/ssl/fake/fake.key;
location / {
proxy_pass http://localhost:8575/;
include /etc/nginx/conf.d/proxy.conf;
}
)
Updated Personal Blog --> https://www.freesoftwareservers.com/display/FREES/Use+CertBot+-+LetsEncrypt+-+In+StandAlone+Docker+Container
Related
I am running a HTTPS webserver. On the same host, I would like to run a docker container registry.
According to this tutorial, I need to run this command:
docker run -d \
--restart=always \
--name registry \
-v "$(pwd)"/certs:/certs \
-e REGISTRY_HTTP_ADDR=0.0.0.0:443 \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
-e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
-p 443:443 \
registry:2
But my nginx server already has 443 bound. So I guess I can't run the container registry with this port. What are my options here? Can I just use something other than 443?
You could use Nginx as a proxyserver and have (sub)domains pointing to the two different services (Webserver and Docker Container Registry)
Step 1 : Set up domainnames
DNS: registry.mycompany.com to IP address of the Host
DNS: www.mycompany.com to IP address of the Host
Step 2 : Config Nginx as a proxyserver
Nginx sites.conf
# Main Server
server {
listen 80 default_server;
server_name _;
return 301 https://$host$request_uri;
}
# The Webserver
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name www.mycompany.com;
ssl_certificate /etc/ssl/private/star_mycompany_com.chained.crt;
ssl_certificate_key /etc/ssl/private/star_mycompany_com.key;
access_log /var/log/nginx/webserver_access.log;
error_log /var/log/nginx/webserver_error.log;
location / {
proxy_pass http://172.30.0.3:80/;
}
}
# The Registry
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name registry.mycompany.com;
ssl_certificate /etc/ssl/private/star_mycompany_com.chained.crt;
ssl_certificate_key /etc/ssl/private/star_mycompany_com.key;
access_log /var/log/nginx/registry_access.log;
error_log /var/log/nginx/registry_error.log;
location / {
proxy_pass http://172.30.0.2:80/;
}
}
In your docker-compose.yml of the registry, put it on IP 172.30.0.2,
and in the docker-compose.yml of the webserver, put it on IP 172.30.0.3
Step 3 : Run Nginx itself in a Docker Container
docker-compose.yml
version: "3.9"
services:
proxyserver:
image: nginx:latest
container_name: Proxyserver
working_dir: /usr/share/nginx/html
ports:
- "80:80"
- "443:443"
volumes:
- ./etc/nginx/conf.d:/etc/nginx/conf.d:ro
- ./etc/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./etc/ssl/private:/etc/ssl/private
- ./var/log/nginx:/var/log/nginx
networks:
my-net:
ipv4_address: 172.30.0.254
networks:
my-net:
external: true
name: cops-net
Step 4 : Create your external Docker Network
create_network.sh
docker network create \
--driver=bridge \
--subnet=172.30.0.0/16 \
--attachable \
--gateway=172.30.0.1 \
my-net
Step 5 : Start everything up
Start the container with the webserver
Start the container with the registry
Start the proxyserver
My Problem:
I am using Ubuntu 18.04 and a docker-compose based solution with two Docker images, one to handle Python/uWSGI and one for my NGINX reverse proxy. No matter what I change, it always seems like WSGI is unable to detect my default application. Whenever I run docker-compose up, and navigate to localhost:5000 I get the above default splash.
The complete program appears to work on our CentOS 7 machines. However, when I try to execute it on my Ubuntu test machine, I can only get the "Welcome to NGINX!" page.
Directory Structure:
/app
- app.conf
- app.ini
- app.py
- docker-compose.py
- Dockerfile-flask
- Dockerfile-nginx
- requirements.txt
/templates
(All code snippets have been simplified to help isolate the problem)
Here is an example of my docker traceback:
clocker_flask_1
[uWSGI] getting INI configuration from app.ini
current working directory: /app
detected binary path: /usr/local/bin/uwsgi
uwsgi socket 0 bound to TCP address 0.0.0.0:5000 fd 3
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) ***
*** Operational MODE: preforking+threaded ***
WSGI app 0 (mountpoint='') ready in 1 seconds on interpreter 0x558072010e70 pid: 1 (default app)
clocker_nginx_1
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
Here is my docker-compose.yaml:
# docker-compose.yml
version: '3'
services:
flask:
image: webapp-flask
build:
context: .
dockerfile: Dockerfile-flask
volumes:
- "./:/app:z"
- "/etc/localtime:/etc/localtime:ro"
environment:
- "EXTERNAL_IP=${EXTERNAL_IP}"
nginx:
image: webapp-nginx
build:
context: .
dockerfile: Dockerfile-nginx
ports:
- 5000:80
depends_on:
- flask
Dockerfile-flask:
FROM python:3
ENV APP /app
RUN mkdir $APP
WORKDIR $APP
EXPOSE 5000
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD [ "uwsgi", "--ini", "app.ini" ]
Dockerfile-nginx
FROM nginx:latest
EXPOSE 80
COPY app.conf /etc/nginx/conf.d
app.conf
server {
listen 80;
root /usr/share/nginx/html;
location / { try_files $uri #app; }
location #app {
include uwsgi_params;
uwsgi_pass flask:5000;
}
}
app.py
# Home bit
#application.route('/')
#application.route('/home', methods=["GET", "POST"])
def home():
return render_template(
'index.html',
er = er
)
if __name__ == "__main__":
application.run(host='0.0.0.0')
app.ini
[uwsgi]
protocol = uwsgi
module = app
callable = application
master = true
processes = 2
threads = 2
socket = 0.0.0.0:5000
vacuum = true
die-on-term = true
max-requests = 1000
The nginx image comes with a main configuration file, /etc/nginx/nginx.conf, which loads every conf file in the conf.d folder -- including your nemesis in this case, a stock /etc/nginx/conf.d/default.conf. It reads as follows (trimmed a bit for concision):
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
}
So, your app.conf and this configuration are both active. The reason why this default one wins, though, is because of the server_name directive that it has (and yours lacks) -- when you're hitting localhost:5000, nginx matches based on the hostname and sends your request there.
To fix this easily, you can just remove that file in your Dockerfile-nginx:
RUN rm /etc/nginx/conf.d/default.conf
I have an EC2 instance on AWS that runs Amazon Linux 2.
On it, I installed Git, docker, and docker-compose. Once done, I cloned my repository and ran docker-compose up to get my production environment up. I go to the public DNS, and it works.
I now want to enable HTTPS onto the site.
My project has a frontend using React to run on an Nginx-alpine server. The backend is a NodeJS server.
This is my nginx.conf file:
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri /index.html;
}
location /api/ {
proxy_pass http://${PROJECT_NAME}_backend:${NODE_PORT}/;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
Here's my docker-compose.yml file:
version: "3.7"
services:
##############################
# Back-End Container
##############################
backend: # Node-Express backend that acts as an API.
container_name: ${PROJECT_NAME}_backend
init: true
build:
context: ./backend/
target: production
restart: always
environment:
- NODE_PATH=${EXPRESS_NODE_PATH}
- AWS_REGION=${AWS_REGION}
- NODE_ENV=production
- DOCKER_BUILDKIT=1
- PORT=${NODE_PORT}
networks:
- client
##############################
# Front-End Container
##############################
nginx:
container_name: ${PROJECT_NAME}_frontend
build:
context: ./frontend/
target: production
args:
- NODE_PATH=${REACT_NODE_PATH}
- SASS_PATH=${SASS_PATH}
restart: always
environment:
- PROJECT_NAME=${PROJECT_NAME}
- NODE_PORT=${NODE_PORT}
- DOCKER_BUILDKIT=1
command: /bin/ash -c "envsubst '$$PROJECT_NAME $$NODE_PORT' < /etc/nginx/conf.d/nginx.template > /etc/nginx/conf.d/default.conf && exec nginx -g 'daemon off;'"
expose:
- "80"
ports:
- "80:80"
depends_on:
- backend
networks:
- client
##############################
# General Config
##############################
networks:
client:
I know there's a Docker image for certbot, but I'm not sure how to use it. I'm also worried about the way I'm proxying requests to /api/ to the server over http. Will that also give me any problems?
Edit:
Attempt #1: Traefik
I created a Traefik container to route all traffic through HTTPS.
version: '2'
services:
traefik:
image: traefik
restart: always
ports:
- 80:80
- 443:443
networks:
- web
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /opt/traefik/traefik.toml:/traefik.toml
- /opt/traefik/acme.json:/acme.json
container_name: traefik
networks:
web:
external: true
For the toml file, I added the following:
debug = false
logLevel = "ERROR"
defaultEntryPoints = ["https","http"]
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.http.redirect]
entryPoint = "https"
[entryPoints.https]
address = ":443"
[entryPoints.https.tls]
[retry]
[docker]
endpoint = "unix:///var/run/docker.sock"
domain = "ec2-00-000-000-00.eu-west-1.compute.amazonaws.com"
watch = true
exposedByDefault = false
[acme]
storage = "acme.json"
entryPoint = "https"
onHostRule = true
[acme.httpChallenge]
entryPoint = "http"
I added this to my docker-compose production file:
labels:
- "traefik.docker.network=web"
- "traefik.enable=true"
- "traefik.basic.frontend.rule=Host:ec2-00-000-000-00.eu-west-1.compute.amazonaws.com"
- "traefik.basic.port=80"
- "traefik.basic.protocol=https"
I ran docker-compose up for the Traefik container, and then ran docker-compose up on my production image. I got the following error:
unable to obtain acme certificate
I'm reading the Traefik docs and apparently there's a way to configure the toml file specifically for Amazon ECS: https://docs.traefik.io/configuration/backends/ecs/
Am I on the right track?
Easiest way would be to setup a ALB and use it for HTTPS.
Create ALB
Add 443 Listener to ALB
Generate Certificate using AWS Certificate Manager
Set the Certificate to the default cert for the load balancer
Create Target Group
Add your EC2 Instance to the Target Group
Point the ALB to the Target Group
Requests will be served using the ALB with https
Enabling SSL is done through following the tutorial on Nginx and Let's Encrypt with Docker in Less Than 5 Minutes. I ran into some issues while following it, so I will try to clarify some things here.
The steps include adding the following to the docker-compose.yml:
##############################
# Certbot Container
##############################
certbot:
image: certbot/certbot:latest
volumes:
- ./frontend/data/certbot/conf:/etc/letsencrypt
- ./frontend/data/certbot/www:/var/www/certbot
As for the Nginx Container section of the docker-compose.yml, it should be amended to include the same volumes added to the Certbot Container, as well as add the ports and expose configurations:
service_name:
container_name: container_name
image: nginx:alpine
command: /bin/ash -c "exec nginx -g 'daemon off;'"
volumes:
- ./data/certbot/conf:/etc/letsencrypt
- ./data/certbot/www:/var/www/certbot
expose:
- "80"
- "443"
ports:
- "80:80"
- "443:443"
networks:
- default
The data folder may be saved anywhere else, but make sure to know where it is and make sure to reference it properly when reused later. In this example, I am simply saving it in the same directory as the docker-compose.yml file.
Once the above configurations are put into place, a couple of steps are to be taken in order to initialize the issuance of the certificates.
Firstly, your Nginx configuration (default.conf) is to be changed to accommodate the domain verification request:
server {
listen 80;
server_name example.com www.example.com;
server_tokens off;
location / {
return 301 https://$server_name$request_uri;
}
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
}
server {
listen 443 ssl;
server_name example.com www.example.com;
server_tokens off;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri /index.html;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
Once the Nginx configuration file is amended, a dummy certificate is created to allow for Let's Encrypt validation to take place. There is a script that does all of this automatically, which can be downloaded, into the root of the project, using CURL, before being amended to suit the environment. The script would also need to be made executable using the chmod command:
curl -L https://raw.githubusercontent.com/wmnnd/nginx-certbot/master/init-letsencrypt.sh > init-letsencrypt.sh && chmod +x init-letsencrypt.sh
Once the script is downloaded, it is to be amended as follows:
#!/bin/bash
if ! [ -x "$(command -v docker-compose)" ]; then
echo 'Error: docker-compose is not installed.' >&2
exit 1
fi
-domains=(example.org www.example.org)
+domains=(example.com www.example.com)
rsa_key_size=4096
-data_path="./data/certbot"
+data_path="./data/certbot"
-email="" # Adding a valid address is strongly recommended
+email="admin#example.com" # Adding a valid address is strongly recommended
staging=0 # Set to 1 when testing setup to avoid hitting request limits
if [ -d "$data_path" ]; then
read -p "Existing data found for $domains. Continue and replace existing certificate? (y/N) " decision
if [ "$decision" != "Y" ] && [ "$decision" != "y" ]; then
exit
fi
fi
if [ ! -e "$data_path/conf/options-ssl-nginx.conf" ] || [ ! -e "$data_path/conf/ssl-dhparams.pem" ]; then
echo "### Downloading recommended TLS parameters ..."
mkdir -p "$data_path/conf"
curl -s https://raw.githubusercontent.com/certbot/certbot/master/certbot-nginx/certbot_nginx/tls_configs/options-ssl-nginx.conf > "$data_path/conf/options-ssl-nginx.conf"
curl -s https://raw.githubusercontent.com/certbot/certbot/master/certbot/ssl-dhparams.pem > "$data_path/conf/ssl-dhparams.pem"
echo
fi
echo "### Creating dummy certificate for $domains ..."
path="/etc/letsencrypt/live/$domains"
mkdir -p "$data_path/conf/live/$domains"
-docker-compose run --rm --entrypoint "\
+docker-compose -f docker-compose.yml run --rm --entrypoint "\
openssl req -x509 -nodes -newkey rsa:1024 -days 1\
-keyout '$path/privkey.pem' \
-out '$path/fullchain.pem' \
-subj '/CN=localhost'" certbot
echo
echo "### Starting nginx ..."
-docker-compose up --force-recreate -d nginx
+docker-compose -f docker-compose.yml up --force-recreate -d service_name
echo
echo "### Deleting dummy certificate for $domains ..."
-docker-compose run --rm --entrypoint "\
+docker-compose -f docker-compose.yml run --rm --entrypoint "\
rm -Rf /etc/letsencrypt/live/$domains && \
rm -Rf /etc/letsencrypt/archive/$domains && \
rm -Rf /etc/letsencrypt/renewal/$domains.conf" certbot
echo
echo "### Requesting Let's Encrypt certificate for $domains ..."
#Join $domains to -d args
domain_args=""
for domain in "${domains[#]}"; do
domain_args="$domain_args -d $domain"
done
# Select appropriate email arg
case "$email" in
"") email_arg="--register-unsafely-without-email" ;;
*) email_arg="--email $email" ;;
esac
# Enable staging mode if needed
if [ $staging != "0" ]; then staging_arg="--staging"; fi
-docker-compose run --rm --entrypoint "\
+docker-compose -f docker-compose.yml run --rm --entrypoint "\
certbot certonly --webroot -w /var/www/certbot \
$staging_arg \
$email_arg \
$domain_args \
--rsa-key-size $rsa_key_size \
--agree-tos \
--force-renewal" certbot
echo
echo "### Reloading nginx ..."
-docker-compose exec nginx nginx -s reload
+docker-compose exec service_name nginx -s reload
I have made sure to always include the -f flag with the docker-compose command just in case someone doesn't know what to change if they had a custom named docker-compose.yml file. I have also made sure to set the service name as service_name to make sure to differentiate between the service name and the Nginx command, unlike the tutorial.
Note: If unsure about the fact that the setup is working, make sure to set staging as 1 to avoid hitting request limits. It is important to remember to set it back to 0 once testing is done and redo all steps from amending the init-letsencrypt.sh file. Once testing is done and the staging is set to 0, it is important to stop previous running containers and delete the data folder for the proper initial certification to ensue:
$ docker-compose -f docker-compose.yml down && yes | docker system prune -a --volumes && sudo rm -rf ./data
Once the certificates are ready to be initialized, the script is to be run using sudo; it is very important to use sudo, as issues will occur with the permissions inside the containers if run without it.
$ sudo ./init-letsencrypt.sh
After the certificate is issued, there is the matter of automatically renewing the certificate; two things need to be done:
In the Nginx Container, Nginx would reload the newly obtained certificates through the following ammendment:
service_name:
...
- command: /bin/ash -c "exec nginx -g 'daemon off;'"
+ command: /bin/ash -c "while :; do sleep 6h & wait $${!}; nginx -s reload; done & exec nginx -g 'daemon off;'"
...
In the Certbot Container section, the following is to be add to check if the certificate is up for renewal every twelve hours, as recommended by Let's Encrypt:
certbot:
...
+ entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew --webroot -w /var/www/certbot; sleep 12h & wait $${!}; done;'"
Before running docker-compose -f docker-compose.yml up, the ownership of the data should be changed folder to the ec2-user; this is to avoid running into permission errors when running docker-compose -f docker-compose.yml up, or running it in sudo mode:
sudo chown ec2-user:ec2-user -R /path/to/data/
Don't forget to add a CAA record in your DNS provider for Let's Encrypt. You may read here for more information on how to do so.
If you run into any issues with the Nginx container because you are substituting variables and $server_name and $request_uri are not appearing properly, you may refer to this issue.
I have a couple web-domains behind a reverse proxy in Docker... As context, here's a snippet from the docker-compose.yml:
version: '2'
services:
nginx-proxy:
image: jwilder/nginx-proxy
container_name: nginxREVERSE
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
site1:
container_name: 'nginxsite1'
image: nginx:latest
volumes:
- ./sites-available/site1.com/index.html:/usr/share/nginx/html/index.html
- ./sites-available/site1.com/nginx.conf:/etc/nginx/conf.d/default.conf
ports:
- 8080:80
environment:
- VIRTUAL_HOST=site1.com,www.site1.com
- VIRTUAL_PORT:80
- VIRTUAL_PORT:443
site2:
container_name: 'nginxsite2'
image: nginx:latest
volumes:
- ./sites-available/site2.com/index.html:/usr/share/nginx/html/index.html
ports:
- 8082:80
environment:
- VIRTUAL_HOST=site2.com,www.site2.com
- VIRTUAL_PORT:80
And this works perfectly in my browser. I can go to site1.com/www.site1.com or site2.com/www.site2.com and I get proxied to the correct Index.html page.
Site1.com's nginx.conf file:
server {
listen 80;
listen [::]:80;
server_name site1.com www.site1.com;
location ~ /.well-known/acme-challenge {
allow all;
root /usr/share/nginx/html;
}
root /usr/share/nginx/html;
index index.html;
}
I'm running Certbot in docker using this command:
sudo docker run -it --rm \
-v /docker-volumes/etc/letsencrypt:/etc/letsencrypt \
-v /docker-volumes/var/lib/letsencrypt:/var/lib/letsencrypt \
-v /docker/letsencrypt-docker-nginx/src/letsencrypt/letsencrypt-site:/data/letsencrypt \
-v "/docker-volumes/var/log/letsencrypt:/var/log/letsencrypt" \
certbot/certbot \
certonly --webroot \
--register-unsafely-without-email --agree-tos \
--webroot-path=/data/letsencrypt \
--staging \
-d site1.com -d www.site1.com
When I port forward from the router to site1.com container directly, above works.
When I port forward to the reverse proxy, I get this 404 error from Certbot:
Failed authorization procedure. site1.com (http-01): urn:ietf:params:acme:error:unauthorized :: The client lacks sufficient authorizatin :: Invalid response from http://site1.com/.well-known/acme-challenge/x05mYoqEiWlrRFH9ye6VZfEiX-mlwEffVt2kP3twoOU: "<html>\r\n<head><ttle>404 Not Found</title></head>\r\n<body>\r\n<center><h1>404 Not Found</h1></center>\r\n<hr><center>nginx/1.15.5</ce", www.site1.com (ttp-01): urn:ietf:params:acme:error:unauthorized :: The client lacks sufficient authorization :: Invalid response from http://www.site1/.well-known/acme-challenge/AIDgGYg1WiQRm4-dOVK6fV8-vKqR940nLPzT9poFUZA: "<html>\r\n<head><title>404 Not Found</title></head>\r\n<body>r\n<center><h1>404 Not Found</h1></center>\r\n<hr><center>nginx/1.15.5</ce"
IMPORTANT NOTES:
- The following errors were reported by the server:
Domain: site1.com
Type: unauthorized
Detail: Invalid response from
http://site1.com/.well-known/acme-challenge/x05mYoqEiWlrRFH9ye6VZfEiX-mlwEOU:
"<html>\r\n<head><title>404 Not
Found</title></head>\r\n<body>\r\n<center><h1>404 Not
Found</h1></center>\r\n<hr><center>nginx/1.15.5</ce"
Domain: www.site1.com
Type: unauthorized
Detail: Invalid response from
http://www.site1.com/.well-known/acme-challenge/AIDgGYg1WiQRm4-dOVK6fV8-poFUZA:
"<html>\r\n<head><title>404 Not
Found</title></head>\r\n<body>\r\n<center><h1>404 Not
Found</h1></center>\r\n<hr><center>nginx/1.15.5</ce"
To fix these errors, please make sure that your domain name was
entered correctly and the DNS A/AAAA record(s) for that domain
contain(s) the right IP address.
What am I missing that allows me to access the sites behind the reverse proxy from my browser but won't allow Cerbot?
The challenge location in your Site1.com's nginx.conf file don't match with the certbot option --webroot-path. It's for that you get a 404 error.
Next a posible correction.
Site1.com's nginx.conf file:
server {
listen 80;
listen [::]:80;
server_name site1.com www.site1.com;
location ~ /.well-known/acme-challenge {
alias /usr/share/nginx/html;
try_files $uri =404;
}
root /usr/share/nginx/html;
index index.html;
}
Certbot in docker using this command:
sudo docker run -it --rm \
-v /docker-volumes/etc/letsencrypt:/etc/letsencrypt \
-v /docker-volumes/var/lib/letsencrypt:/var/lib/letsencrypt \
-v /docker/letsencrypt-docker-nginx/src/letsencrypt/letsencrypt-site:/data/letsencrypt \
-v "/docker-volumes/var/log/letsencrypt:/var/log/letsencrypt" \
certbot/certbot \
certonly --webroot \
--register-unsafely-without-email --agree-tos \
--webroot-path=/usr/share/nginx/html \
--staging \
-d site1.com -d www.site1.com
I have a web application based on php and nginx images ... Everything works great until I set a command under the PHP configuration:
command: /usr/bin/supervisord -c /symfony/supervisord.conf
docker-compose.yml
version: '2'
services:
php:
build: docker/php
tty: true
volumes:
- '.:/symfony'
command: /usr/bin/supervisord -c /symfony/supervisord.conf
nginx:
image: nginx:1.11
tty: true
volumes:
- './public/:/symfony'
- './docker/nginx/default.conf:/etc/nginx/conf.d/default.conf'
ports:
- '80:80'
links:
- php
This is my default.conf
server {
server_name ~.*;
location / {
root /symfony;
try_files $uri /index.php$is_args$args;
}
location ~ ^/index\.php(/|$) {
client_max_body_size 50m;
fastcgi_pass php:9000;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME /symfony/public/index.php;
}
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
}
This is my supervisord.conf
[unix_http_server]
file=/tmp/supervisor.sock
[supervisord]
logfile=/tmp/supervisord.log
pidfile=/var/run/supervisord.pid
nodaemon=true
Nginx logs show me:
nginx_1 | 2018/10/02 00:42:36 [error] 11#11: 1 connect() failed
(111: Connection refused) while connecting to upstream, client:
172.23.0.1, server: ~., request: "GET / HTTP/1.1", upstream: "fastcgi://172.23.0.2:9000", host: "127.0.0.1"
As we see, nginx report a 502 Bad Gateway error. If i remove the last line, CMD, everything works fine. If I remove the line and I acess via docker-compose exec php bash and launch the command manually everything work also.
Any Idea why adding that command leads to 502 Bad Gateway ??
Ok I found a solution It was a problem with supervisor. Because each time we launch our service supervisor, the php-fpm service is stopped automatically that's why it should add a configuration that will relaunch the php-fpm but this time from supervisor configuration.
[program:php-fpm]
command = /usr/local/sbin/php-fpm
autostart=true
autorestart=true
For anyone else with similar problem:
Don't forget that command key in docker-compose.yml file overrides default CMD in Dockerfile, therefore that command won't be run.
For example, if php:7.4-fpm final command is CMD php-fpm, it won't be run.
Therefore if you have some custom logic for running after container is ran, don't forget to include it in your command, e.g.:
command: bash -c "php-fpm & npm run dev"