Private domain with LE certificate

I use a public domain e.g. example.com. The LE certificate is renewed regularly. Everything works great. I have now created the subdomain foo.example.com, but the subdomain is private. I want the subdomain to use the LE certificate as well. How to do it ?
Certificates are renewed automatically or I can renew them manually

sudo certbot --nginx

or

sudo certbot --nginx -d example.com -d www.example.com

I can't use -d foo.eample.com right now because it's a private subdomain. I tried this

sudo certbot --nginx -d *.example.com   

The result is

Client with the currently selected authenticator does not support any combination of challenges that will satisfy the CA. You may need to use an authenticator plugin that can do challenges over DNS.
Client with the currently selected authenticator does not support any combination of challenges that will satisfy the CA. You may need to use an authenticator plugin that can do challenges over DNS.

2 Likes

For a wildcard certificate, the dns-01 challenge is required. See Challenge Types - Let's Encrypt for the different type of challenges. You can read more about which plugin supports what challenge in certbot here: User Guide — Certbot 1.22.0 documentation

5 Likes

For publicly registered domains and subdomains that are privately mapped with DNS (eg. foo.example.com), you can also obtain a LE Certificate for the privately mapped domain on a dedicated LE Certificate by using the DNS-01 challenge option. Sometimes that is a better option to manage certificates than relying on a wildcard LE Certificate (which also requires a DNS-01 challenge).

6 Likes

I have a registered domain on freenom.
I read here that there is no dns plugin for freenom.
Do I have to change name servers to cloudflare?
There is also a solution to github, but I haven't tried it.

1 Like

Can you authenticate via HTTP?

3 Likes

Well, good luck with that, as at the moment from my point of view all the FreeNom nameservers are unreachable :frowning:Nevermind that, a few minutes later all are up again.. But it does show you shouldn't be surprised if they don't work again in the future.

2 Likes

Yes I can

1 Like

Then you don't need a DNS plugin.

2 Likes

Can you advise me some step-by-step instructions?
thx

2 Likes

Rudy, @gusto1 seems to be wanting a wildcard certificate. Probably due to the fact the subdomain is private.

4 Likes

Yes, subdomain is private.

2 Likes

I've tested that certbot-dns-freenom plugin and it works. --dns-freenom-propagation-seconds should be set quite high though, in my testing 600 seconds worked.

However, I only know how to install it on Gentoo or through pip (it's available on certbot-dns-freenom · PyPI). If you've installed certbot through snap, I don't know how you can use third party plugins.

3 Likes

I use LXC debian.

pip install certbot certbot-dns-freenom
Collecting certbot
  Using cached https://files.pythonhosted.org/packages/f9/46/9805cbeb9db85d5702b14295fdf97a71926a3d789776d57a10d4c098ddb1/certbot-1.11.0-py2.py3-none-any.whl
Collecting certbot-dns-freenom
  Using cached https://files.pythonhosted.org/packages/5d/39/4ac5557ce56b8d7fb8b804c78975e7d24375e4d75c2eec979ba2ba373853/certbot-dns-freenom-1.3.2.tar.gz
Collecting distro>=1.0.1 (from certbot)
  Using cached https://files.pythonhosted.org/packages/b3/8d/a0a5c389d76f90c766e956515d34c3408a1e18f60fbaa08221d1f6b87490/distro-1.6.0-py2.py3-none-any.whl
Collecting parsedatetime>=1.3 (from certbot)
  Using cached https://files.pythonhosted.org/packages/a8/20/cb587f6672dbe585d101f590c3871d16e7aec5a576a1694997a3777312ac/parsedatetime-2.6.tar.gz
Collecting zope.component (from certbot)
  Using cached https://files.pythonhosted.org/packages/36/79/3114deb9f4e6ff724868c200ceaba7b43df427d750315519fe91879afa9c/zope.component-5.0.1-py2.py3-none-any.whl
Collecting pytz (from certbot)
  Using cached https://files.pythonhosted.org/packages/d3/e3/d9f046b5d1c94a3aeab15f1f867aa414f8ee9d196fae6865f1d6a0ee1a0b/pytz-2021.3-py2.py3-none-any.whl
Requirement already satisfied: setuptools in /usr/lib/python2.7/dist-packages (from certbot) (40.8.0)
Collecting ConfigArgParse>=0.9.3 (from certbot)
  Using cached https://files.pythonhosted.org/packages/16/05/385451bc8d20a3aa1d8934b32bd65847c100849ebba397dbf6c74566b237/ConfigArgParse-1.5.3.tar.gz
Collecting josepy>=1.1.0 (from certbot)
  Using cached https://files.pythonhosted.org/packages/5e/a6/2c573bf13b720e129054a2581a569000d86653515d1cf9ee76a3727ec9c3/josepy-1.6.0-py2.py3-none-any.whl
Collecting zope.interface (from certbot)
  Using cached https://files.pythonhosted.org/packages/47/55/20205df173d5c544a0002ee4b8f3aa862e3f1e2a0994a76ceed1587017f2/zope.interface-5.4.0-cp27-cp27mu-manylinux1_x86_64.whl
Collecting pyrfc3339 (from certbot)
  Using cached https://files.pythonhosted.org/packages/c1/7a/725f5c16756ec6211b1e7eeac09f469084595513917ea069bc023c40a5e2/pyRFC3339-1.1-py2.py3-none-any.whl
Collecting acme>=1.8.0 (from certbot)
  Using cached https://files.pythonhosted.org/packages/74/66/08ef1275daace2d7d46eef8e6209be4c243c8ac9105ee95c3aaac3b943a4/acme-1.11.0-py2.py3-none-any.whl
Collecting configobj (from certbot)
  Using cached https://files.pythonhosted.org/packages/64/61/079eb60459c44929e684fa7d9e2fdca403f67d64dd9dbac27296be2e0fab/configobj-5.0.6.tar.gz
Requirement already satisfied: cryptography>=1.2.3 in /usr/lib/python2.7/dist-packages (from certbot) (2.6.1)
Collecting mock; python_version < "3.3" (from certbot)
  Using cached https://files.pythonhosted.org/packages/05/d2/f94e68be6b17f46d2c353564da56e6fb89ef09faeeff3313a046cb810ca9/mock-3.0.5-py2.py3-none-any.whl
Collecting freenom (from certbot-dns-freenom)
  Could not find a version that satisfies the requirement freenom (from certbot-dns-freenom) (from versions: )
No matching distribution found for freenom (from certbot-dns-freenom)

2 Likes

I would not use pip to install certbot if you already installed it some other way, as having two instances of certbot could interfer.

Also, strange error, as the freenom plugin is available on PyPi: freenom · PyPI So pip should be able to install it.. Works perfectly on my system:

osiris@erazer tmp $ python -m venv freenom
osiris@erazer tmp $ cd freenom/
osiris@erazer freenom $ source bin/activate
(freenom) osiris@erazer freenom $ pip install certbot-dns-freenom
Collecting certbot-dns-freenom
  Using cached certbot-dns-freenom-1.3.3.tar.gz (4.1 kB)
Collecting certbot>=1.3.0
  Using cached certbot-1.22.0-py2.py3-none-any.whl (270 kB)
Collecting freenom
  Using cached freenom-0.0.2-py3-none-any.whl (5.7 kB)
Requirement already satisfied: setuptools in ./lib/python3.9/site-packages (from certbot-dns-freenom) (56.0.0)
Collecting zope.interface
  Using cached zope.interface-5.4.0-cp39-cp39-manylinux2010_x86_64.whl (255 kB)
Collecting parsedatetime>=2.4
  Using cached parsedatetime-2.6-py3-none-any.whl (42 kB)
Collecting pyrfc3339
  Using cached pyRFC3339-1.1-py2.py3-none-any.whl (5.7 kB)
Collecting zope.component
  Using cached zope.component-5.0.1-py2.py3-none-any.whl (68 kB)
Collecting ConfigArgParse>=0.9.3
  Using cached ConfigArgParse-1.5.3-py3-none-any.whl (20 kB)
Collecting configobj>=5.0.6
  Using cached configobj-5.0.6-py3-none-any.whl
Collecting acme>=1.22.0
  Using cached acme-1.22.0-py2.py3-none-any.whl (46 kB)
Collecting josepy>=1.9.0
  Using cached josepy-1.11.0-py2.py3-none-any.whl (29 kB)
Collecting pytz
  Using cached pytz-2021.3-py2.py3-none-any.whl (503 kB)
Collecting distro>=1.0.1
  Using cached distro-1.6.0-py2.py3-none-any.whl (19 kB)
Collecting cryptography>=2.5.0
  Using cached cryptography-36.0.1-cp36-abi3-manylinux_2_24_x86_64.whl (3.6 MB)
Collecting requests-toolbelt>=0.3.0
  Using cached requests_toolbelt-0.9.1-py2.py3-none-any.whl (54 kB)
Collecting PyOpenSSL>=17.3.0
  Using cached pyOpenSSL-21.0.0-py2.py3-none-any.whl (55 kB)
Collecting requests>=2.14.2
  Using cached requests-2.26.0-py2.py3-none-any.whl (62 kB)
Collecting six
  Using cached six-1.16.0-py2.py3-none-any.whl (11 kB)
Collecting cffi>=1.12
  Using cached cffi-1.15.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl (444 kB)
Collecting pycparser
  Using cached pycparser-2.21-py2.py3-none-any.whl (118 kB)
Collecting charset-normalizer~=2.0.0
  Using cached charset_normalizer-2.0.9-py3-none-any.whl (39 kB)
Collecting urllib3<1.27,>=1.21.1
  Using cached urllib3-1.26.7-py2.py3-none-any.whl (138 kB)
Collecting idna<4,>=2.5
  Using cached idna-3.3-py3-none-any.whl (61 kB)
Collecting certifi>=2017.4.17
  Using cached certifi-2021.10.8-py2.py3-none-any.whl (149 kB)
Collecting lxml>=4.5.0
  Using cached lxml-4.7.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl (6.9 MB)
Collecting retrying>=1.3.3
  Using cached retrying-1.3.3.tar.gz (10 kB)
Collecting zope.hookable>=4.2.0
  Using cached zope.hookable-5.1.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl (27 kB)
Collecting zope.event
  Using cached zope.event-4.5.0-py2.py3-none-any.whl (6.8 kB)
Using legacy 'setup.py install' for certbot-dns-freenom, since package 'wheel' is not installed.
Using legacy 'setup.py install' for retrying, since package 'wheel' is not installed.
Installing collected packages: pycparser, cffi, urllib3, six, idna, cryptography, charset-normalizer, certifi, requests, pytz, PyOpenSSL, zope.interface, zope.hookable, zope.event, requests-toolbelt, pyrfc3339, josepy, zope.component, retrying, parsedatetime, lxml, distro, configobj, ConfigArgParse, acme, freenom, certbot, certbot-dns-freenom
    Running setup.py install for retrying ... done
    Running setup.py install for certbot-dns-freenom ... done
Successfully installed ConfigArgParse-1.5.3 PyOpenSSL-21.0.0 acme-1.22.0 certbot-1.22.0 certbot-dns-freenom-1.3.3 certifi-2021.10.8 cffi-1.15.0 charset-normalizer-2.0.9 configobj-5.0.6 cryptography-36.0.1 distro-1.6.0 freenom-0.0.2 idna-3.3 josepy-1.11.0 lxml-4.7.1 parsedatetime-2.6 pycparser-2.21 pyrfc3339-1.1 pytz-2021.3 requests-2.26.0 requests-toolbelt-0.9.1 retrying-1.3.3 six-1.16.0 urllib3-1.26.7 zope.component-5.0.1 zope.event-4.5.0 zope.hookable-5.1.0 zope.interface-5.4.0
WARNING: You are using pip version 21.1.3; however, version 21.3.1 is available.
You should consider upgrading via the '/tmp/freenom/bin/python -m pip install --upgrade pip' command.
(freenom) osiris@erazer freenom $ certbot plugins

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* dns-freenom
Description: Obtain certificates using a DNS TXT record (if you are using
Freenom for DNS).
Interfaces: Authenticator, Plugin
Entry point: dns-freenom = certbot_dns_freenom.dns_freenom:Authenticator

* standalone
Description: Spin up a temporary webserver
Interfaces: Authenticator, Plugin
Entry point: standalone = certbot._internal.plugins.standalone:Authenticator

* webroot
Description: Place files in webroot directory
Interfaces: Authenticator, Plugin
Entry point: webroot = certbot._internal.plugins.webroot:Authenticator
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(freenom) osiris@erazer freenom $

Although... I see you're running Python 2.7? Well.. That could be an issue indeed.. But you shouldn't be running Python 2.7 any longer in the first place..

3 Likes

Everything worked out, but I'm confused.
Is this procedure correct?
I have 1x public domain
example.com
I renew the certificate as follows
sudo certbot --nginx
I created a private subdomain on apache2

sudo mkdir /var/www/html/www.example.com/subdomain
sudo nano /etc/apache2/sites-available/subdomain.example.com.conf


<VirtualHost *:80>
    ServerAdmin admin@subdomain.example.com
    ServerName subdomain.example.com
    DocumentRoot /var/www/html/www.example.com/subdomain/
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

sudo chown www-data:www-data -R /var/www/html/www.example.com/subdomain
sudo a2ensite subdomain.example.com.conf
sudo systemctl reload apache2

I created a server block in the reverse proxy nginx for the subdomain.

sudo nano /etc/nginx/sites-available/subdomain.example.com


server {
    listen 80;
    server_name subdomain.example.com;
 
    location / {
        proxy_pass http://192.168.1.106;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

sudo nginx -t
sudo ln -s /etc/nginx/sites-available/subdomain.example.com /etc/nginx/sites-enabled/subdomain.example.com
sudo systemctl reload nginx

On pfsense, I configured a host override for the subdomain. Everything works great, of course without LE cert. The subdomain only needs to work on the LAN.

Now I'm going to generate a certificate for no public domain (resp. wildcard).

sudo certbot -d *.example.com --manual --preferred-challenges dns certonly
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator manual, Installer None
Obtaining a new certificate
Performing the following challenges:
dns-01 challenge for example.com

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NOTE: The IP of this machine will be publicly logged as having requested this
certificate. If you're running certbot in manual mode on a machine that is not
your server, please ensure you're okay with that.

Are you OK with your IP being logged?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: y

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please deploy a DNS TXT record under the name
_acme-challenge.example.com with the following value:

X7RMZ1ompP_xXGWWPPT8TVUQ8fvGPAg-PkaxsadZFIo

Before continuing, verify the record is deployed.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue


Waiting for verification...
Cleaning up challenges

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/example.com-0001/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/example.com-0001/privkey.pem
   Your cert will expire on 2022-04-03. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot
   again. To non-interactively renew *all* of your certificates, run
   "certbot renew"
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

I manually modified the configuration for the server block.

server {
    server_name subdomain.example.com;

    location / {
        proxy_pass http://192.168.1.106;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
    
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/example.com-0001/fullchain.pem; 
    ssl_certificate_key /etc/letsencrypt/live/example.com-0001/privkey.pem; 
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
    
}

server {
    if ($host = subdomain.example.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot
 
 
    listen 80;
    server_name subdomain.example.com;
    return 404; # managed by Certbot
 
 
}
sudo systemctl reload nginx

If I enter the url into the browser subdomain.example.com everything works great. Private subdomain works with LE certificate.

I want to create another subdomain and I'm starting to get confused here.

I created another host override (subdomain2) on pfsense.
I created another vhost on apache2

sudo mkdir /var/www/html/www.example.com/subdomain2
sudo nano /etc/apache2/sites-available/subdomain2.example.com.conf


<VirtualHost *:80>
    ServerAdmin admin@subdomain2.example.com
    ServerName subdomain2.example.com
    DocumentRoot /var/www/html/www.example.com/subdomain2/
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

sudo chown www-data:www-data -R /var/www/html/www.example.com/subdomain2
sudo a2ensite subdomain2.example.com.conf
sudo systemctl reload apache2

If I enter the url subdomain2.example.com into the browser, it also works.
I don't understand how this can work when it doesn't already exist in the reverse proxy server block for this subdomain.

I don't think it should work.

It "works" because when a web server can't specifically match a vhost by SNI it will use the "default" vhost. Since nginx likely only has the one vhost, it will match it or it will default to it and all requests will end up going to the same place.

5 Likes

If I create other subdomains, I have to create vhosts in apache2 and server blocks in nginx reverse proxy for each subdomain.
Then will it work properly?

2 Likes

That is how it should be.
Each name that requires unique content must have its' own document root (which requires its' own vhost config).
The proxy must also keep that separation (which requires it also have separate vhosts).

3 Likes

On apache2 backend servers, I will use a unique configuration for each vhost.
I don't know if this is the right solution, but I only used one config file in the reverse proxy for subdomains.

server {
    server_name subdomain.example.com;

    location / {
        proxy_pass http://192.168.1.106;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
    
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/example.com-0001/fullchain.pem; 
    ssl_certificate_key /etc/letsencrypt/live/example.com-0001/privkey.pem; 
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
    
}

server {
    if ($host = subdomain.example.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot
 
 
    listen 80;
    server_name subdomain.example.com;
    return 404; # managed by Certbot
 
 
}

If I replace in the configuration file

subdomain.example.com

these alternatives

.example.com
*.example.com
example.com

It always works properly. I'm confused as to whether I'm set it right or wrong.

In which web server (nginx or Apache or both)?

2 Likes