Convert Figma logo to code with AI

diafygi logoacme-tiny

A tiny script to issue and renew TLS certs from Let's Encrypt

4,725
572
4,725
17

Top Related Projects

31,293

Certbot is EFF's tool to obtain certs from Let's Encrypt and (optionally) auto-enable HTTPS on your server. It can also act as a client for any other CA that uses the ACME protocol.

letsencrypt/acme client implemented as a shell-script – just add water

38,464

A pure Unix shell script implementing ACME client protocol

🛡️ A private certificate authority (X.509 & SSH) & ACME server for secure automated certificate management, so you can use TLS everywhere & SSO for SSH.

7,845

Let's Encrypt/ACME client and library written in Go

Quick Overview

Acme-tiny is a minimalist Python script for obtaining and renewing Let's Encrypt certificates. It's designed to be simple, lightweight, and easy to understand, with a focus on security and minimal dependencies.

Pros

  • Extremely lightweight (less than 200 lines of code)
  • Easy to audit and understand due to its simplicity
  • Minimal dependencies (only requires Python and OpenSSL)
  • Can be easily integrated into existing systems or automated workflows

Cons

  • Limited features compared to more comprehensive ACME clients
  • Requires manual setup and configuration of web server for challenges
  • No built-in automatic renewal (requires external scheduling)
  • May not be suitable for users who prefer a more feature-rich or GUI-based solution

Code Examples

  1. Generate account key:
openssl genrsa 4096 > account.key
  1. Generate domain key and CSR:
openssl genrsa 4096 > domain.key
openssl req -new -sha256 -key domain.key -subj "/CN=example.com" > domain.csr
  1. Run acme-tiny to obtain certificate:
python acme_tiny.py --account-key ./account.key --csr ./domain.csr --acme-dir /var/www/challenges/ > ./signed.crt

Getting Started

  1. Clone the repository:

    git clone https://github.com/diafygi/acme-tiny.git
    cd acme-tiny
    
  2. Generate account and domain keys (as shown in code examples above)

  3. Configure your web server to serve challenge files from a directory (e.g., /var/www/challenges/)

  4. Run acme-tiny to obtain your certificate:

    python acme_tiny.py --account-key ./account.key --csr ./domain.csr --acme-dir /var/www/challenges/ > ./signed.crt
    
  5. Configure your web server to use the new certificate

  6. Set up a cron job or other scheduler to run acme-tiny periodically for renewals

Competitor Comparisons

31,293

Certbot is EFF's tool to obtain certs from Let's Encrypt and (optionally) auto-enable HTTPS on your server. It can also act as a client for any other CA that uses the ACME protocol.

Pros of certbot

  • More comprehensive features, including automatic renewal and web server configuration
  • Supports a wide range of web servers and operating systems
  • Offers a user-friendly CLI and interactive mode for easier certificate management

Cons of certbot

  • Larger codebase and more dependencies, potentially increasing complexity
  • May require root access for certain operations, which could be a security concern
  • Heavier resource usage compared to lightweight alternatives

Code comparison

acme-tiny:

def get_crt(account_key, csr, acme_dir, log=LOGGER, CA=DEFAULT_CA):
    # ... (simplified core functionality in ~100 lines)

certbot:

def obtain_cert(config, plugins, lineage=None):
    # ... (more complex implementation with additional features)
    installer.deploy_cert(domain, fullchain_path, key_path, cert_path, chain_path)
    installer.save()
    installer.restart()

acme-tiny focuses on a single, concise function for obtaining certificates, while certbot offers a more extensive API with additional features like deployment and server configuration.

letsencrypt/acme client implemented as a shell-script – just add water

Pros of dehydrated

  • More feature-rich, supporting multiple domains and wildcard certificates
  • Includes hooks for custom actions during the certificate issuance process
  • Offers a wider range of configuration options

Cons of dehydrated

  • More complex setup and usage compared to acme-tiny
  • Larger codebase, potentially harder to audit for security-conscious users
  • Requires more dependencies and system resources

Code Comparison

acme-tiny:

def get_crt(account_key, csr, acme_dir, log=LOGGER, CA=DEFAULT_CA):
    # ... (simplified for brevity)
    return signed_crt

dehydrated:

sign_csr() {
    local domain="${1}" acme_keyfile="${2}" acme_openssl_cnf="${3}" cert="${4}" key="${5}"
    # ... (simplified for brevity)
}

The code snippets highlight the different approaches:

  • acme-tiny uses a single Python function for the entire process
  • dehydrated employs multiple shell functions for different steps

Both projects aim to simplify Let's Encrypt certificate issuance, but dehydrated offers more features at the cost of increased complexity, while acme-tiny focuses on simplicity and minimal dependencies.

38,464

A pure Unix shell script implementing ACME client protocol

Pros of acme.sh

  • More feature-rich, supporting multiple DNS providers and automatic renewals
  • Written in shell script, making it more portable across different systems
  • Actively maintained with frequent updates and a larger community

Cons of acme.sh

  • More complex setup and configuration compared to acme-tiny
  • Larger codebase, which may be overwhelming for users seeking a simple solution
  • Requires more system resources due to its comprehensive feature set

Code Comparison

acme-tiny:

def get_crt(account_key, csr, acme_dir, log=LOGGER, CA=DEFAULT_CA):
    # Simple Python implementation
    # ... (code omitted for brevity)

acme.sh:

_initpath() {
  # Complex shell script implementation
  # ... (code omitted for brevity)
}

acme-tiny focuses on a minimalist Python implementation, while acme.sh uses shell scripting for broader compatibility and more extensive features. acme-tiny's code is generally more concise and easier to understand, whereas acme.sh's codebase is larger and more complex due to its comprehensive functionality.

🛡️ A private certificate authority (X.509 & SSH) & ACME server for secure automated certificate management, so you can use TLS everywhere & SSO for SSH.

Pros of certificates

  • More comprehensive certificate management solution, offering a wider range of features beyond just ACME
  • Supports multiple certificate authorities and protocols, not limited to Let's Encrypt
  • Provides a CLI tool and API for easier integration and automation

Cons of certificates

  • Larger and more complex codebase, potentially harder to audit and maintain
  • Requires more dependencies and system resources to run
  • May be overkill for simple use cases where only basic ACME functionality is needed

Code comparison

acme-tiny:

def get_crt(account_key, csr, acme_dir, log=LOGGER, CA=DEFAULT_CA):
    # ... (simplified ACME certificate issuance process)
    return signed_crt

certificates:

func (c *Client) Sign(req *SignRequest) (*Certificate, error) {
    // ... (more complex certificate signing process with additional options)
    return cert, nil
}

The code comparison shows that acme-tiny focuses on a simple, single-function approach for obtaining certificates, while certificates offers a more feature-rich and flexible API for certificate management.

7,845

Let's Encrypt/ACME client and library written in Go

Pros of lego

  • More comprehensive feature set, supporting multiple DNS providers and challenge types
  • Actively maintained with regular updates and a larger community
  • Provides a CLI tool and can be used as a library in Go projects

Cons of lego

  • Larger codebase and more complex to understand and modify
  • Requires Go runtime, which may increase resource usage
  • May be overkill for simple certificate issuance needs

Code comparison

acme-tiny:

def get_crt(account_key, csr, acme_dir, log=LOGGER, CA=DEFAULT_CA):
    # ... (implementation details)
    return signed_crt

lego:

func (c *Client) ObtainCertificate(domains []string, bundle bool, privKey crypto.PrivateKey, mustStaple bool) (*CertificateResource, error) {
    // ... (implementation details)
    return certRes, nil
}

Both projects aim to simplify the process of obtaining SSL/TLS certificates from Let's Encrypt, but they differ in scope and implementation. acme-tiny is a minimalist Python script focused solely on certificate issuance, while lego is a more feature-rich Go library and CLI tool that offers additional functionality beyond basic certificate management.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

acme-tiny

Tests Coverage Status

This is a tiny, auditable script that you can throw on your server to issue and renew Let's Encrypt certificates. Since it has to be run on your server and have access to your private Let's Encrypt account key, I tried to make it as tiny as possible (currently less than 200 lines). The only prerequisites are python and openssl.

PLEASE READ THE SOURCE CODE! YOU MUST TRUST IT WITH YOUR PRIVATE ACCOUNT KEY!

Donate

If this script is useful to you, please donate to the EFF. I don't work there, but they do fantastic work.

https://eff.org/donate/

How to use this script

If you already have a Let's Encrypt issued certificate and just want to renew, you should only have to do Steps 3 and 6.

Step 1: Create a Let's Encrypt account private key (if you haven't already)

You must have a public key registered with Let's Encrypt and sign your requests with the corresponding private key. If you don't understand what I just said, this script likely isn't for you! Please use the official Let's Encrypt client. To accomplish this you need to initially create a key, that can be used by acme-tiny, to register an account for you and sign all following requests.

openssl genrsa 4096 > account.key

Use existing Let's Encrypt key

Alternatively you can convert your key, previously generated by the original Let's Encrypt client.

The private account key from the Let's Encrypt client is saved in the JWK format. acme-tiny is using the PEM key format. To convert the key, you can use the tool conversion script by JonLundy:

# Download the script
wget -O - "https://gist.githubusercontent.com/JonLundy/f25c99ee0770e19dc595/raw/6035c1c8938fae85810de6aad1ecf6e2db663e26/conv.py" > conv.py

# Copy your private key to your working directory
cp /etc/letsencrypt/accounts/acme-v01.api.letsencrypt.org/directory/<id>/private_key.json private_key.json

# Create a DER encoded private key
openssl asn1parse -noout -out private_key.der -genconf <(python2 conv.py private_key.json)

# Convert to PEM
openssl rsa -in private_key.der -inform der > account.key

Step 2: Create a certificate signing request (CSR) for your domains.

The ACME protocol (what Let's Encrypt uses) requires a CSR file to be submitted to it, even for renewals. You can use the same CSR for multiple renewals. NOTE: you can't use your account private key as your domain private key!

# Generate a domain private key (if you haven't already)
openssl genrsa 4096 > domain.key
# For a single domain
openssl req -new -sha256 -key domain.key -subj "/CN=yoursite.com" > domain.csr

# For multiple domains (use this one if you want both www.yoursite.com and yoursite.com)
openssl req -new -sha256 -key domain.key -subj "/" -addext "subjectAltName = DNS:yoursite.com, DNS:www.yoursite.com" > domain.csr

# For multiple domains (same as above but works with openssl < 1.1.1)
openssl req -new -sha256 -key domain.key -subj "/" -reqexts SAN -config <(cat /etc/ssl/openssl.cnf <(printf "[SAN]\nsubjectAltName=DNS:yoursite.com,DNS:www.yoursite.com")) > domain.csr

Step 3: Make your website host challenge files

You must prove you own the domains you want a certificate for, so Let's Encrypt requires you host some files on them. This script will generate and write those files in the folder you specify, so all you need to do is make sure that this folder is served under the ".well-known/acme-challenge/" url path. NOTE: Let's Encrypt will perform a plain HTTP request to port 80 on your server, so you must serve the challenge files via HTTP (a redirect to HTTPS is fine too).

# Make some challenge folder (modify to suit your needs)
mkdir -p /var/www/challenges/
# Example for nginx
server {
    listen 80;
    server_name yoursite.com www.yoursite.com;

    location /.well-known/acme-challenge/ {
        alias /var/www/challenges/;
        try_files $uri =404;
    }

    ...the rest of your config
}

Step 4: Get a signed certificate!

Now that you have setup your server and generated all the needed files, run this script on your server with the permissions needed to write to the above folder and read your private account key and CSR.

# Run the script on your server
python acme_tiny.py --account-key ./account.key --csr ./domain.csr --acme-dir /var/www/challenges/ > ./signed_chain.crt

Step 5: Install the certificate

The signed https certificate chain that is output by this script can be used along with your private key to run an https server. You need to include them in the https settings in your web server's configuration. Here's an example on how to configure an nginx server:

server {
    listen 443 ssl;
    server_name yoursite.com www.yoursite.com;

    ssl_certificate /path/to/signed_chain.crt;
    ssl_certificate_key /path/to/domain.key;
    ssl_session_timeout 5m;
    ssl_protocols TLSv1.2;
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
    ssl_session_cache shared:SSL:50m;
    ssl_dhparam /path/to/server.dhparam;
    ssl_prefer_server_ciphers on;

    ...the rest of your config
}

server {
    listen 80;
    server_name yoursite.com www.yoursite.com;

    location /.well-known/acme-challenge/ {
        alias /var/www/challenges/;
        try_files $uri =404;
    }

    ...the rest of your config
}

Step 6: Setup an auto-renew cronjob

Congrats! Your website is now using https! Unfortunately, Let's Encrypt certificates only last for 90 days, so you need to renew them often. No worries! It's automated! Just make a bash script and add it to your crontab (see below for example script).

Example of a renew_cert.sh:

#!/usr/bin/sh
python /path/to/acme_tiny.py --account-key /path/to/account.key --csr /path/to/domain.csr --acme-dir /var/www/challenges/ > /path/to/signed_chain.crt.tmp || exit
mv /path/to/signed_chain.crt.tmp /path/to/signed_chain.crt
service nginx reload
# Example line in your crontab (runs once per month)
0 0 1 * * /path/to/renew_cert.sh 2>> /var/log/acme_tiny.log

NOTE: Since Let's Encrypt's ACME v2 release (acme-tiny 4.0.0+), the intermediate certificate is included in the issued certificate download, so you no longer have to independently download the intermediate certificate and concatenate it to your signed certificate. If you have an shell script or Makefile using acme-tiny <4.0 (e.g. before 2018-03-17) with acme-tiny 4.0.0+, then you may be adding the intermediate certificate to your signed_chain.crt twice (which causes issues with at least GnuTLS 3.7.0 besides making the certificate slightly larger than it needs to be). To fix, simply remove the bash code where you're downloading the intermediate and adding it to the acme-tiny certificate output.

Permissions

The biggest problem you'll likely come across while setting up and running this script is permissions. You want to limit access to your account private key and challenge web folder as much as possible. I'd recommend creating a user specifically for handling this script, the account private key, and the challenge folder. Then add the ability for that user to write to your installed certificate file (e.g. /path/to/signed_chain.crt) and reload your webserver. That way, the cron script will do its thing, overwrite your old certificate, and reload your webserver without having permission to do anything else.

BE SURE TO:

  • Backup your account private key (e.g. account.key)
  • Don't allow this script to be able to read your domain private key!
  • Don't allow this script to be run as root!

Staging Environment

Let's Encrypt recommends testing new configurations against their staging servers, so when testing out your new setup, you can use --directory-url https://acme-staging-v02.api.letsencrypt.org/directory to issue fake test certificates instead of real ones from Let's Encrypt's production servers. See https://letsencrypt.org/docs/staging-environment/ for more details.

Feedback/Contributing

This project has a very, very limited scope and codebase. I'm happy to receive bug reports and pull requests, but please don't add any new features. This script must stay under 200 lines of code to ensure it can be easily audited by anyone who wants to run it.

If you want to add features for your own setup to make things easier for you, please do! It's open source, so feel free to fork it and modify as necessary.