{"id":17527055,"url":"https://github.com/spaze/letsgetacert","last_synced_at":"2025-04-08T18:31:59.255Z","repository":{"id":13503484,"uuid":"71081300","full_name":"spaze/letsgetacert","owner":"spaze","description":"Let's get cert – a Certbot wrapper","archived":false,"fork":false,"pushed_at":"2023-08-01T16:18:18.000Z","size":47,"stargazers_count":23,"open_issues_count":0,"forks_count":2,"subscribers_count":6,"default_branch":"main","last_synced_at":"2023-08-01T18:49:22.975Z","etag":null,"topics":["certbot","certificate","https","letsencrypt","ssl","tls"],"latest_commit_sha":null,"homepage":null,"language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/spaze.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-10-16T22:31:26.000Z","updated_at":"2021-10-05T17:01:53.000Z","dependencies_parsed_at":"2024-11-06T12:37:45.483Z","dependency_job_id":"8338c5aa-85e3-403c-92f3-bd3ac144a3b3","html_url":"https://github.com/spaze/letsgetacert","commit_stats":null,"previous_names":[],"tags_count":0,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spaze%2Fletsgetacert","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spaze%2Fletsgetacert/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spaze%2Fletsgetacert/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spaze%2Fletsgetacert/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/spaze","download_url":"https://codeload.github.com/spaze/letsgetacert/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247902301,"owners_count":21015426,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["certbot","certificate","https","letsencrypt","ssl","tls"],"created_at":"2024-10-20T15:03:01.322Z","updated_at":"2025-04-08T18:31:54.245Z","avatar_url":"https://github.com/spaze.png","language":"Shell","funding_links":[],"categories":["Shell"],"sub_categories":[],"readme":"# Let's Get a Cert\nA [Certbot](https://certbot.eff.org/) wrapper to process certificate configuration files and to generate certificates if needed. Can execute a \"hook\" after it has finished.\n\n# Prerequisites\n1. [Certbot](https://certbot.eff.org/) installed and registered with the CA (`certbot-auto register`)\n2. A webserver with HTTPS support enabled, make sure `.well-known` directory in the document root is accessible and the URLs are not rewritten\n3. OpenSSL 1.1.1 or newer\n\n# Installation\n1. Clone this repository somewhere\n2. Copy `letsgetacert.cnf.template` to `letsgetacert.cnf`\n3.  Edit `letsgetacert.cnf`, see configuration options below\n4. Create certificate configuration files for your certificates and domains\n5. Run `letsgetacert --verbose --no-cert` to see if the certificate configuration files are processed correctly\n6. Run `letsgetacert --verbose` to get your certificates if needed\n7. If everything is ok place `letsgetacert` to your crontab so that it get's executed daily; no need to run with superuser privileges, `sudo` is used when needed\n\n## Usage\n```\nletsgetacert [-c|--config CONFIGFILE] [-e|--list-expires] [-f|--force COMMONNAME] [-n|--no-cert] [-v|--verbose]\n```\n\n```\n-c, --c CONFIGFILE\n```\nRead `CONFIGFILE` instead of `letsgetacert.cnf` in the `letsgetacert` directory.\n\n```\n-e, --list-expires\n```\nOnly list expire dates; `--force` and `--no-cert` do nothing when used together with `--list-expires`.\n\n```\n-f, --force COMMONNAME\n```\nGet certificate for `COMMONNAME` even if it's not expired yet, for example when you want to add a new SAN (Subject Alternative Name).\n\n```\n-n, --no-cert\n```\nDon't generate a CSR, don't get a certificate, like a *dry run* for testing.\n\n```\n-v, --verbose\n```\nBe verbose and report what's going on.\n\n## Configuration file options\n### Example file\n```\nEXPIRY_THRESHOLD=30\nCONFDIR=/home/ubuntu/.letsgetacert\nCERTBOT=/opt/certbot/certbot-auto\nCERTBOT_EXTRA_OPTS=\"--test-cert --quiet\"\nSUBJECT_EMAIL=bot@example.com\nfunction hook {\n    sudo service nginx reload\n}\nfunction pre_getcert_hook {\n    sudo -H /opt/eff.org/certbot/venv/bin/pip install certbot-dns-cloudflare\n}\n```\n\n### Options with example values\n```\nEXPIRY_THRESHOLD=30\n```\nRenew certs this many days before the expiration date.\n\n```\nCONFDIR=/home/ubuntu/.letsgetacert\n```\nWhere to look for the certificate config files.\n\n```\nCERTBOT=/opt/certbot/certbot-auto\n```\nHow to execute Certbot.\n\n```\nCERTBOT_EXTRA_OPTS=\"--test-cert --quiet\"\n```\nCertbot extra options, `--test-cert` is for generating invalid, testing certificates.\n\n```\nSUBJECT_EMAIL=bot@example.com\n```\nEmail to be used in certificate subject field.\n\n```\nfunction hook {\n    sudo service nginx reload\n}\n```\nCall this function when at least one cert was generated successfully or not; use it to reload your web server configuration; you can also use these variables in the hook function:\n\n- `$NEW_CERTS_CNEXT`: array of common names (plus *filename extensions*) from generated certificates\n- `$NEW_CERTS_CN`: array of just the common names\n- `$NEW_CERTS_EXT`: array of just the *file extensions*\n- `$NEW_CERTS_START`: array of start dates of the newly generated certificates, in seconds since the epoch\n- `$NEW_CERTS_EXPIRY`: array of expiration dates of the newly generated certificates, in seconds since the epoch\n- `$FAILED_CERTS_CNEXT`: array of common names (plus *filename extensions*) from certificates which were not generated due to a failure\n- `$FAILED_CERTS_CN`: array of just the common names\n- `$FAILED_CERTS_EXT`: array of just the *file extensions*\n\n```\nfunction pre_getcert_hook {\n    sudo -H /opt/eff.org/certbot/venv/bin/pip install certbot-dns-cloudflare\n}\n```\nThis function is called before obtaining a certificate (i.e. before generating a key \u0026 CSR, and before executing Certbot). You can use it to reinstall plugins when using `certbot-auto` which wipes all plugins on upgrade. It will not be called when no certificate is to be obtained (for example because none is expiring soon).\n\n#### Hook example\nThis (bit more complicated) hook example will reload nginx configuration when at least one certificate was generated successfully, and `POST` a report together with a `user` and a `key` to the specified URL:\n```\nfunction hook {\n        sudo service nginx reload\n        PARAMS=\"--data user=foo --data key=bar\"\n        for I in \"${!NEW_CERTS_CNEXT[@]}\"; do\n                PARAMS=\"${PARAMS} --data certs[${NEW_CERTS_CNEXT[$I]}][cn]=${NEW_CERTS_CN[$I]} --data certs[${NEW_CERTS_CNEXT[$I]}][ext]=${NEW_CERTS_EXT[$I]} --data certs[${NEW_CERTS_CNEXT[$I]}][start]=${NEW_CERTS_START[$I]} --data certs[${NEW_CERTS_CNEXT[$I]}][expiry]=${NEW_CERTS_EXPIRY[$I]}\"\n        done\n        for I in \"${!FAILED_CERTS_CNEXT[@]}\"; do\n                PARAMS=\"${PARAMS} --data failure[${FAILED_CERTS_CNEXT[$I]}][cn]=${FAILED_CERTS_CN[$I]} --data failure[${FAILED_CERTS_CNEXT[$I]}][ext]=${FAILED_CERTS_EXT[$I]}\"\n        done\n        curl \\\n        --location \\\n        --silent \\\n        --user-agent \"Let's Get a Cert\" \\\n        --write-out \"\\n%{url_effective} -\u003e HTTP %{http_code} (in %{time_total}s)\\n\" \\\n        $PARAMS \\\n        https://example.com/report-certificate\n}\n```\n\n## Example certificate configuration file\nName the file after the `CN` field, use `.cnf` extension when saving and place the file in the `CONFDIR` directory (or create a symlink), in this case the filename should be `example.com.cnf`:\n```\nCN=example.com\n# PRIVKEY=/etc/nginx/certs/$CN.privkey.pem\nPRIVKEY_CMD=\"genrsa -out %s 2048\"\nCERT_DIR=/etc/nginx/certs\nSUBJECT=\"/C=CZ/ST=Prague/L=Prague/O=example.com/emailAddress=$SUBJECT_EMAIL/CN=$CN\"\nWEBROOT_DIR=/srv/www/$CN/site/public\nDOMAINS=\"www=example.com,www.example.com;foo=foo.example.com;bar=bar.example.com\"\nEXT=ecdsa\nCHALLENGE=\"http-01\"\nCERTBOT_DNS_CHALLENGE_OPTS=\"\"\n```\n\n### Options\n```\nCN=example.com\n```\nCertificate common name.\n\n```\nPRIVKEY=/etc/nginx/certs/$CN.privkey.pem\n```\nPath to private key, must exist before generating certs. Cannot be used together with `PRIVKEY_CMD`. Can be used to emulate or instead of Certbot's `--reuse-key` (available since 0.25.0).\n\n```\nPRIVKEY_CMD=\"genrsa -out %s 2048\"\n```\nA command to generate the private key, will be prefixed with `sudo openssl`, `%s` is a placeholder for the file where the key will be stored and is replaced automatically. Use for example `PRIVKEY_CMD=\"ecparam -genkey -name prime256v1 -out %s\"` to generate an elliptic curve private key. The command will be executed every time before getting a new cert. Cannot be used together with `PRIVKEY`.\n\n```\nCERT_DIR=/etc/nginx/certs\n```\nWhere to put generated certs and private keys, must contain `archive` subdirectory; files are put into the `archive` directory, `CERT_DIR` will contain symbolic links.\n\n```\nSUBJECT=\"/C=CZ/ST=Prague/L=Prague/O=example.com/emailAddress=$SUBJECT_EMAIL/CN=$CN\"\n```\nCertificate subject; you can use `$SUBJECT_EMAIL` and `$CN` variables.\n\n```\nWEBROOT_DIR=/srv/www/$CN/site/public\n```\nPath to where the web root directories are placed.\n\n```\nDOMAINS=\"www=example.com,www.example.com;foo=foo.example.com;bar=bar.example.com\"\n```\nConfiguration of domains for the certificate, these will be placed in the Subject Alternative Name (SAN) field; the format is `DIR=DOMAINS`, Certbot will look for verification files in `WEBROOT_DIR/DIR/.well-known` directory for `DOMAINS`; separate multiple domains with comma (`,`), multiple `DIR=DOMAINS` with semicolon (`;`).\n\n```\nEXT=ecdsa\n```\nOptional *filename extension* displayed in verbose messages, can be used when there are multiple certs for the same domain (e.g. dual RSA and ECDSA certs).\n\n```\nCHALLENGE=\"dns-01\"\n```\nOptional [challenge type](https://certbot.eff.org/docs/challenges.html) (`http-01` and `dns-01` are supported, `http-01` is used when no `CHALLENGE` is specified).\n\n```\nCERTBOT_DNS_CHALLENGE_OPTS=\"--dns-cloudflare --dns-cloudflare-credentials ~/.secrets/cloudflare.ini\"\n```\nCertbot challenge options, `--dns-cloudflare` telling certbot to use cloudflare plugin, required for `dns-01`. Since Certbot 1.6.0, you can and should use Cloudflare's limited-scope API Tokens, not the Global API key, read the [Cloudflare DNS plugin docs](https://certbot-dns-cloudflare.readthedocs.io/en/stable/) for more info.\n\n## Seamless transition\nYou can use your existing certificates and keys with `letsgetacert`, just create a symbolic link in the `CERT_DIR`. The name should follow this pattern: `$CN.fullchain.pem`. Then the file will be picked up by `letsgetacert` automatically and if the certificate is going to expire soon it will be renewed using Certbot.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspaze%2Fletsgetacert","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fspaze%2Fletsgetacert","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspaze%2Fletsgetacert/lists"}