{"id":13586880,"url":"https://github.com/valpackett/freshcerts","last_synced_at":"2025-08-18T01:33:42.448Z","repository":{"id":39662923,"uuid":"47724675","full_name":"valpackett/freshcerts","owner":"valpackett","description":"ACME certificate protocol (Let's Encrypt) proxy client with a dashboard and monitoring","archived":false,"fork":false,"pushed_at":"2025-02-12T19:28:18.000Z","size":72,"stargazers_count":60,"open_issues_count":4,"forks_count":11,"subscribers_count":5,"default_branch":"trunk","last_synced_at":"2025-08-09T03:36:03.987Z","etag":null,"topics":["acme","certificate","dashboard","letsencrypt","monitoring","security","ssl","tls"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/valpackett.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":"CODE_OF_CONDUCT.md","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,"zenodo":null}},"created_at":"2015-12-09T23:04:45.000Z","updated_at":"2024-10-23T19:44:17.000Z","dependencies_parsed_at":"2025-08-09T03:36:00.140Z","dependency_job_id":"af691f82-8e62-403f-b4a2-158b71d2a0ee","html_url":"https://github.com/valpackett/freshcerts","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/valpackett/freshcerts","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/valpackett%2Ffreshcerts","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/valpackett%2Ffreshcerts/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/valpackett%2Ffreshcerts/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/valpackett%2Ffreshcerts/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/valpackett","download_url":"https://codeload.github.com/valpackett/freshcerts/tar.gz/refs/heads/trunk","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/valpackett%2Ffreshcerts/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270932567,"owners_count":24670240,"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","status":"online","status_checked_at":"2025-08-17T02:00:09.016Z","response_time":129,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["acme","certificate","dashboard","letsencrypt","monitoring","security","ssl","tls"],"created_at":"2024-08-01T15:05:52.689Z","updated_at":"2025-08-18T01:33:42.436Z","avatar_url":"https://github.com/valpackett.png","language":"Ruby","funding_links":[],"categories":["Ruby"],"sub_categories":[],"readme":"# freshcerts [![unlicense](https://img.shields.io/badge/un-license-green.svg?style=flat)](http://unlicense.org)\n\n![Screenshot](https://files.app.net/h02q76bXk.png)\n\n[ACME](https://letsencrypt.github.io/acme-spec/) (currently implemented by [Let's Encrypt](https://letsencrypt.org)) is a way to automatically (re)issue TLS certificates.\n\nMost ACME clients are designed to run on the same machine as your TLS services. \nBut if you have a lot of servers, there are two problems with that:\n- you either have to copy your account private key onto all of them, or register multiple accounts;\n- you don't have a nice monitoring dashboard \u0026 notifications!\n\nfreshcerts solves both problems.\nIt runs a server that exposes a much simpler API to your servers (they'll use a tiny shell script that's pretty much `openssl | curl | tar`) and a dashboard to your system administrators.\nServers are monitored to ensure they actually use the certs issued for them.\nEmail notifications are sent to the admins for all errors found by monitoring and for all issued certificates.\n\n## Installation\n\nIt's a typical Ruby app, so you'll need [Bundler](https://bundler.io):\n\n```bash\ngit clone https://github.com/valpackett/freshcerts.git\ncd freshcerts\nbundle install --path vendor/bundle\nmkdir data\n```\n\nUse environment variables to configure the app. Read `common.rb` to see which variables are available.\nYou probably should change the ACME endpoint (by default, Let's Encrypt **staging** is used, not production):\n\n```bash\nexport ACME_ENDPOINT=\"https://acme-v01.api.letsencrypt.org/\"\nexport ADMIN_EMAIL=\"support@example.com\"\n```\n\nGenerate a tokens key:\n\n```bash\nopenssl ecparam -genkey -name prime256v1 -out data/tokens.key.pem\n```\n\nGenerate and register an account key:\n\n```bash\nopenssl genrsa -out data/account.key.pem 4096\nchmod 0400 data/account.key.pem\nbundle exec ./register-account-key\n```\n\nRun:\n\n```bash\nbundle exec puma -p 9393\n```\n\nIn production, you'll want to configure your process manager to run it.\nSet `RACK_ENV=production` there in addition to the config variables (`ACME_ENDPOINT`, etc.)\n\n### Minimizing Memory Footprint\n\nIf you want to run freshcerts on e.g. a cheap VPS with low RAM:\n\n- by default, the monitoring worker runs in a thread inside of the app. You can run it separately with cron:\n  - set `SEPARATE_MONITORING=1` for the server process (puma/rackup);\n  - put `bundle exec ruby monitoring.rb` into your crontab for every 10 minutes or so.\n- run the server process under [soad](https://github.com/valpackett/soad)! It will start the server on demand and shut it down when it's inactive. Don't set the `time-until-stop` to something ridiculously low like 1 second, because freshcerts keeps challenges in memory.\n\nThis way, memory will only be used when there are requests to the freshcerts server or when it's doing the monitoring.\n\n## Usage\n\nFor every domain:\n\nGenerate an auth token with `bundle exec ./generate-token`.\n\nConfigure the HTTP server to forward `/.well-known/acme-challenge/*` requests to the freshcerts server.\n\nConfigure cron to run the `freshcerts-client` script every day.\n\nArgs: domain, subject, ports (comma separated), reload command, auth token. Like this:\n\n```\nFRESHCERTS_HOST=\"https://certs.example.com:4333\" freshcerts-client example.com /CN=example.com 443 \"service nginx reload\" \"eyJ0eXAiOi...\"\n```\n\nAnd figure out cert paths and file permissions :-)\n\n### Multi-domain certificates (SAN, Subject Alternative Name)\n\nIf you want to issue a certificate for multiple domains, there's a more advanced Ruby client, use it like that:\n\n```\nFRESHCERTS_HOST=\"https://certs.example.com:4333\" FRESHCERTS_TOKEN=\"eyJ0eXAiOi...\" freshcerts-multi-client example.com,www.example.com 443 \u0026\u0026 service nginx reload\n```\n\nIf you can't use Ruby, you can modify the shell client to support multi-domain certificates. [Set up openssl.cnf to read SAN from the environment](https://security.stackexchange.com/a/86999), modify the client to read that config section (add e.g. `-extensions san_env` to the CSR generation command) and pass the domains via that variable. For the freshcerts part (first arg), use a comma-separated list of domains instead of just one domain. Do not use `subjectAltName` as a subject field, that's a special syntax supported by *some* CAs (not Let's Encrypt!) that will turn it into real SAN fields.\n\n## Contributing\n\nPlease feel free to submit pull requests!\n\nBy participating in this project you agree to follow the [Contributor Code of Conduct](http://contributor-covenant.org/version/1/4/).\n\n[The list of contributors is available on GitHub](https://github.com/valpackett/freshcerts/graphs/contributors).\n\n## License\n\nThis is free and unencumbered software released into the public domain.  \nFor more information, please refer to the `UNLICENSE` file or [unlicense.org](http://unlicense.org).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvalpackett%2Ffreshcerts","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvalpackett%2Ffreshcerts","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvalpackett%2Ffreshcerts/lists"}