Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@talyguryn
Last active October 29, 2023 08:57
Show Gist options
  • Star 22 You must be signed in to star a gist
  • Fork 15 You must be signed in to fork a gist
  • Save talyguryn/bd0f30ab3eb183afbe9521261adfbc60 to your computer and use it in GitHub Desktop.
Save talyguryn/bd0f30ab3eb183afbe9521261adfbc60 to your computer and use it in GitHub Desktop.
How to get a wildcard ssl certificate and set up Nginx.

How to get and install a wildcard SSL certificate

In this guide you can find how to resolve the following issues.

Feel free to ask any questions in the comments section below.

Request a new certificate

Get certbot

Go to any directory and clone repo with sources.

cd ~
git clone https://github.com/certbot/certbot

Directory certbot will be created.

Request a certificate

Put a domain name into a variable.

DOMAIN=example.com

Go to certbot's directory

cd certbot

Request a certificate for your domains. You don't need to edit this command

./certbot-auto certonly --manual -d *.$DOMAIN -d $DOMAIN --agree-tos --manual-public-ip-logging-ok --preferred-challenges dns-01 --server https://acme-v02.api.letsencrypt.org/directory --register-unsafely-without-email --rsa-key-size 4096

You will see a block with value for a new DNS record.

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

qqiR_lsa2AjMfoVR16mH4UDbOxy_E02l0K1CNyz1RdI

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

Open a DNS panel for you domain name and add a new TXT record. Then go back to the terminal and press Enter. You will be asked to add another one record.

Vscale Panel for example:

Before pressing Enter the second time you can check if records were deployed. Open a new terminal window and run the following command.

host -t txt _acme-challenge.example.com

You will see a response from the DNS with your values.

_acme-challenge.example.com descriptive text "qqiR_lsa2AjMfoVR16mH4UDbOxy_E02l0K1CNyz1RdI"
_acme-challenge.example.com descriptive text "oMmMa-fDLlebdUhvhMD5MinJ2EeFpdP0F9lUPTShh4w"

If these records are correct then press Enter and see the result of issuing.

Waiting for verification...
Cleaning up challenges

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/example.com/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/example.com/privkey.pem
   Your cert will expire on 2018-06-11. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot-auto
   again. To non-interactively renew *all* of your certificates, run
   "certbot-auto 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

Congratulations. You have got a new wildcard certificate for your domain (example.com) and its second-level subdomains (*.example.com).

Set up Nginx

Now we need to add a new snippet with ssl-params.

Go to snippets directory and create a new one.

cd /etc/nginx/snippets
nano ssl.conf

Add the following lines, save and exit the editor (Ctrl+X, Y, Enter).

ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets on;

ssl_protocols TLSv1.2;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES256-SHA384;
ssl_ecdh_curve secp384r1;
ssl_prefer_server_ciphers on;

ssl_stapling on;
ssl_stapling_verify on;

add_header Strict-Transport-Security "max-age=15768000; includeSubdomains; preload";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;

Then you have to create a directory for certificates snippets.

mkdir certs
cd certs

Create a new file that will hold certificate's params.

nano example.com

Add paths to the wildcard certificate.

ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/fullchain.pem;

Usage

Now you have to include params in site's config.

Separated http and https servers

server {
    # Listen default port for http
    listen 80;

    # Server name for this config
    server_name example.com;

    # Force redirect to https
    rewrite ^ https://$server_name$request_uri? permanent;
}

server {
    # Listen https connections
    listen 443 ssl;

    # Server name for this config
    server_name example.com;

    # Include common ssl params
    include snippets/ssl.conf;   

    # Include certificate params
    include snippets/certs/example.com;

    # Your custom nginx params for the site
    # This case returns page with a plain text
    add_header Content-Type text/plain;
    return 200 "Hello, World!";
}

Single server config for a site

server {
    # Listen default port for http
    listen 80;

    # Listen https connections
    listen 443 ssl;

    # Server name for this config
    server_name example.com;

    # Include common ssl params
    include snippets/ssl.conf;   

    # Include certificate params
    include snippets/certs/example.com;

    # Force redirect to https
    if ($scheme != "https") {
        return 301 https://$server_name$request_uri;
    }

    # Your custom nginx params for the site
    # This case returns page with a plain text
    add_header Content-Type text/plain;
    return 200 "Hello, World!";
}

Result

This guide can help you get an A+ rating on test by ssllabs.com

Renewing certificate

There are no methods to automate DNS verification, so at time X you can request a new certificate again via step 2. Local certificate will be updated. Do not forget to reload nginx service.

@hardy4yooz
Copy link

hardy4yooz commented Aug 31, 2018

Hi!
my DOMAIN=abc.def.com (just sample)
./certbot-auto certonly --manual -d '*.abc.def.com' -d 'abc.def.com' --preferred-challenges dns-01 --server https://acme-v02.api.letsencrypt.org/directory

then I add DNS txt twice
all things generated in /etc/letsencrypt/
but I can not get any response with https://xyz.abc.def.com
what is the problem?

@talyguryn
Copy link
Author

Hey, @hardy4yooz

Possible issues

  1. Have you added a DNS record for subdomains?

Try nslookup command to get server's ip by domain name.

If you see an error like this then go to DNS panel and add a record.

** server can't find xyz.abc.def.com: NXDOMAIN

It is enough if you have a record for *.def.com domain.

  1. Does you nginx (or any other web-server) have a config with defined server_name?
server_name xyz.abc.def.com;
  1. Check your default config for sites if it is enabled.

If you have created a config for processing all unhandled domain's requests by other configs (with defined server_name param) then check if you have NOT defined server_name here. Otherwise you'll get an establishing connection error.

# Processes unhandled HTTP requests (port 80)
server {
    listen 80 default_server;

    location / {
        return 307 "https://github.com/talyguryn";
    }
}

# (optional)
# Processes unhandled HTTPS requests (port 443) on taly.space and *.taly.space
# because the certificate was issued only for these domains. For all other unhandled requests
# will be returned an error "Can't establish a secure connection to the server"
server {
    listen 443 ssl default_server;

    include ssl_params_taly;

    location / {
        return 307 "https://github.com/talyguryn";
    }
}

Test it

I just got a certificate for domain abc.taly.space and subdomains *.abc.taly.space without any troubles.

Then I create an example config for server.

server {
    listen 80;
    listen 443 ssl;

    # Listen abc.taly.space and *.abc.taly.space domains
    # Get $subdomain variable from domain name
    server_name ~^(?<subdomain>.+)\.abc\.taly\.space abc.taly.space;

    # Include ssl configs and cert's params
    include snippets/certs/abc_taly;

    # Return data as a plain text
    add_header Content-Type text/plain;

    if ($subdomain = "") {
        return 200 "Welcome to abc.taly.space";
    }

    return 200 "Welcome to $subdomain.abc.taly.space";
}

Now you can test opening page by domain or subdomains.

https://abc.taly.space
https://test.abc.taly.space
https://qwerty123.abc.taly.space

@tihoho
Copy link

tihoho commented Sep 2, 2018

thanks. it's work and without problems for me.

@hardy4yooz
Copy link

@talyguryn
it works!
it’s due to firewall restrictions.
thanks!

@zahinafsar
Copy link

It says NET::ERR_CERT_COMMON_NAME_INVALID

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment