{"id":13564558,"url":"https://github.com/foomo/simplecert","last_synced_at":"2025-05-16T13:05:06.259Z","repository":{"id":38858675,"uuid":"123942956","full_name":"foomo/simplecert","owner":"foomo","description":"golang autocert library for letsencrypt","archived":false,"fork":false,"pushed_at":"2024-03-29T09:53:49.000Z","size":2323,"stargazers_count":215,"open_issues_count":1,"forks_count":36,"subscribers_count":19,"default_branch":"master","last_synced_at":"2025-04-12T08:36:41.492Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","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/foomo.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":"2018-03-05T15:55:48.000Z","updated_at":"2025-04-10T10:20:28.000Z","dependencies_parsed_at":"2024-01-16T18:58:06.322Z","dependency_job_id":"d920988f-cd61-41e4-b77c-ec516662031a","html_url":"https://github.com/foomo/simplecert","commit_stats":null,"previous_names":["foomo/autocert"],"tags_count":36,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foomo%2Fsimplecert","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foomo%2Fsimplecert/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foomo%2Fsimplecert/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foomo%2Fsimplecert/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/foomo","download_url":"https://codeload.github.com/foomo/simplecert/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254535827,"owners_count":22087399,"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":[],"created_at":"2024-08-01T13:01:32.935Z","updated_at":"2025-05-16T13:05:06.213Z","avatar_url":"https://github.com/foomo.png","language":"Go","funding_links":[],"categories":["Go"],"sub_categories":[],"readme":"         _                 _                    _\n     ___(_)_ __ ___  _ __ | | ___  ___ ___ _ __| |_\n    / __| | '_ ` _ \\| '_ \\| |/ _ \\/ __/ _ \\ '__| __|\n    \\__ \\ | | | | | | |_) | |  __/ (_|  __/ |  | |_\n    |___/_|_| |_| |_| .__/|_|\\___|\\___\\___|_|   \\__|\n                    |_|\n\n\u003e Golang Library for automatic LetsEncrypt SSL Certificates\n\n[![Go Report Card](https://goreportcard.com/badge/github.com/foomo/simplecert)](https://goreportcard.com/report/github.com/foomo/simplecert)\n[![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://raw.githubusercontent.com/foomo/simplecert/master/docs/LICENSE)\n[![Golang](https://img.shields.io/badge/Go-1.11-blue.svg)](https://golang.org)\n![Linux](https://img.shields.io/badge/Supports-Linux-green.svg)\n![macOS](https://img.shields.io/badge/Supports-macOS-green.svg)\n![windows](https://img.shields.io/badge/Supports-windows-green.svg)\n[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](https://godoc.org/github.com/foomo/simplecert)\n\nObtains certificates automatically, and manages renewal and hot reload for your Golang application.\nIt uses the [LEGO Library](https://github.com/go-acme/lego) to perform ACME challenges,\nand the [mkcert](https://github.com/FiloSottile/mkcert) utility to generate self-signed trusted certificates for local development.\n\nMain goals:\n\n- ease of use: simplicity and integration with go standard library\n- transparency: products of intermediate steps are preserved, dedicated logfile for simplecert\n- flexibility: configurable design and cross platform support\n\nUPDATE: The vendored lego version has been updated to v2.2.0 and now supports issuing wildcard certificates by using ACMEv2 challenges.\n\nYou need to supply the following data to simplecert: Domains, Contact Email and a Directory to store the certs in (CacheDir).\nOn startup, call the simplecert.Init() function and pass your config.\nYou will receive a certReloader instance, that has a GetCertificateFunc to allow hot reloading the cert upon renewal.\nSee Usage for a detailed example.\n\nA new certificate will be obtained automatically if the domains have changed, both in local and in production mode.\n\nFor more advanced usage, see the config section for all configuration options.\n\n## Index\n\n- [Install](#install)\n- [API](#api)\n- [Local Development](#local-development)\n- [Host Entries](#host-entries)\n- [Usage](#usage)\n- [Challenges](#challenges)\n- [Graceful service shutdown and restart](#graceful-service-shutdown-and-restart)\n- [Backup mechanism](#backup-mechanism)\n- [Configuration](#configuration)\n- [Examples](#examples)\n- [Debug](#debug)\n- [Troubleshooting](#troubleshooting)\n- [License](#license)\n\n## Install\n\n```shell\ngo get -u -v github.com/foomo/simplecert\n```\n\n## API\n\nSimplecert provides a few wrappers similar to *http.ListenAndServe* from the go standard library:\n\nFor running on a production server:\n\n```go\nfunc ListenAndServeTLS(addr string, handler http.Handler, mail string, cleanup func(), domains ...string) error\n```\n\nFor local development:\n\n```go\nfunc ListenAndServeTLSLocal(addr string, handler http.Handler, cleanup func(), domains ...string) error\n```\n\nThe custom wrapper allows to pass a *simplecert.Config* and a *tls.Config*:\n\n```go\nfunc ListenAndServeTLSCustom(addr string, handler http.Handler, cfg *Config, tlsconf *tls.Config, cleanup func(), domains ...string) error\n```\n\nThere is a util for redirecting HTTP requests to HTTPS:\n\n```go\nfunc Redirect(w http.ResponseWriter, req *http.Request)\n```\n\nAnd a function to initialize simplecert after applying the desired configuration:\n\n```go\nfunc Init(cfg *Config, cleanup func()) (*CertReloader, error)\n```\n\n\u003e The cleanup function will be called upon receiving the syscall.SIGINT or syscall.SIGABRT signal and can be used to stop your backend gracefully. If you don't need it, simpy pass nil.\n\n## Local Development\n\nTo make local development less of a pain, simplecert integrates [mkcert](https://github.com/FiloSottile/mkcert),\nto obtain self signed certificates for your desired domains, trusted by your computer.\n\nFollow the [installation instructions](https://github.com/FiloSottile/mkcert#installation) to install the mkcert commandline tool.\n\nIn order to use simplecert for local development, set the *Local* field in the config to true.\n\nCertificates generated for local development are not checked for expiry,\nthe certificates generated by mkcert are valid for 10 years!\n\n**Important**:\n\nUsing wildcard certificates in local mode does not work out of the box, since /etc/hosts doesn't support resolving wild card entries.\n\nYou'll have to use other services like dnsmasq. Just edit dnsmasq.conf and add the following line:\n\n    address=/yourdomain.com/127.0.0.1\n\nThis will resolve all requests to domains that end on *yourdomain.com* with *127.0.0.1*.\n\n### Host Entries\n\nTo resolve the domain name for your certificate to your localhost,\nsimplecert adds an entry for each domain name to your */etc/hosts* file.\n\nThis can be disabled by setting the *UpdateHosts* field in the config to false.\n\n## Usage\n\nSimplecert has a default configuration available: *simplecert.Default*\n\nYou will need to update the *Domains*, *CacheDir* and *SSLEmail* and you are ready to go.\n\n```go\n// init simplecert\ncfg := simplecert.Default\ncfg.Domains = []string{\"yourdomain.com\", \"www.yourdomain.com\"}\ncfg.CacheDir = \"/etc/letsencrypt/live/yourdomain.com\"\ncfg.SSLEmail = \"you@emailprovider.com\"\ncfg.DNSProvider = \"cloudflare\"\ncertReloader, err := simplecert.Init(cfg, nil)\nif err != nil {\n    log.Fatal(\"simplecert init failed: \", err)\n}\n\n// channel to handle errors\nerrChan := make(chan error)\n\n// redirect HTTP to HTTPS\n// CAUTION: This has to be done AFTER simplecert setup\n// Otherwise Port 80 will be blocked and cert registration fails!\nlog.Println(\"starting HTTP Listener on Port 80\")\ngo func(){\n    errChan \u003c- http.ListenAndServe(\":80\", http.HandlerFunc(simplecert.Redirect))\n}()\n\n// init strict tlsConfig with certReloader\n// you could also use a default \u0026tls.Config{}, but be warned this is highly insecure\n// our foomo/tlsconfig provides a simple interface to configure the tls for different scenarios \ntlsconf := tlsconfig.NewServerTLSConfig(tlsconfig.TLSModeServerStrict)\n\n// now set GetCertificate to the reloaders GetCertificateFunc to enable hot reload\ntlsconf.GetCertificate = certReloader.GetCertificateFunc()\n\n// init server\ns := \u0026http.Server{\n    Addr:      \":443\",\n    TLSConfig: tlsconf,\n}\n\n// start serving in a new goroutine\ngo func() {\n    errChan \u003c- s.ListenAndServeTLS(\"\", \"\")\n}()\n\n// fatal on any errors\nlog.Fatal(\u003c-errChan)\n```\n\n## Challenges\n\nSimplecert uses the letsencrypt ACMEv2 API and supports HTTP, TLS and DNS Challenges.\n\nFor the DNS challenge, an API token of an provider must be exported as environment variable.\n\n## Graceful service shutdown and restart\n\nIn case of using the HTTP or TLS challenges, port 80 or 443 must temporarily be freed.\n\nThe *simplecert.Config* contains two functions that can be set to accomplish this:\n\n- WillRenewCertificate, called just before the certificate will be renewed.\n- DidRenewCertificate, called after the certificate was renewed.\n\nThese functions can be used to gracefully stop the running service,\nand bring it back up once the certificate renewal is complete.\n\nIf you want to exchange the certificates manually on disk and force the running service to reload them,\nsimply send a *SIGHUP* signal to your running instance:\n\n    kill -HUP \u003cpid\u003e\n\n## Backup mechanism\n\nSimplecert creates a backup of your old certificate when it is being renewed.\n\nAll data is stored in the configured CacheDir.\n\nIn case something goes wrong while renewing, simplecert will rollback to the original cert.\n\n## Configuration\n\nYou can pass a custom simplecert.Config to suit your needs.\n\nParameters are explained below.\n\n```go\n// Config allows configuration of simplecert\ntype Config struct {\n\n    // renew the certificate X hours before it expires\n    // LetsEncrypt Certs are valid for 90 Days\n    RenewBefore int\n\n    // Interval for checking if cert is closer to expiration than RenewBefore\n    CheckInterval time.Duration\n\n    // SSLEmail for contact\n    SSLEmail string\n\n    // ACME Directory URL. \n    // Can be set to https://acme-staging.api.letsencrypt.org/directory for testing\n    DirectoryURL string\n\n    // Endpoints for webroot challenge\n    // CAUTION: challenge must be received on port 80 and 443\n    // if you choose different ports here you must redirect the traffic\n    HTTPAddress string\n    TLSAddress  string\n\n    // UNIX Permission for the CacheDir and all files inside\n    CacheDirPerm os.FileMode\n\n    // Domains for which to obtain the certificate\n    Domains []string\n\n    // Path of the CacheDir\n    CacheDir string\n\n    // DNSProvider name for DNS challenges (optional)\n    // see: https://godoc.org/github.com/go-acme/lego/providers/dns\n    DNSProvider string\n\n    // Local runmode\n    Local bool\n\n    // UpdateHosts adds the domains to /etc/hosts if running in local mode\n    UpdateHosts bool\n\n    // Handler funcs for graceful service shutdown and restoring\n    WillRenewCertificate func()\n    DidRenewCertificate  func()\n    FailedToRenewCertificate func(error)\n}\n```\n\n## Examples\n\nThe examples directory contains two simple use cases.\n\nA custom initialization:\n\n    go run examples/custom/main.go\n\nAnd a simple example for local development with a locally trusted certificate (requires [mkcert](https://github.com/FiloSottile/mkcert) to be installed):\n\n    go run examples/simple/main.go\n\n## Debug\n\nSimplecert writes all its logs to the *simplecert.log* file inside the configured cache directory.\n\nIt will contain information about certificate status and renewal, as well as errors that occured.\n\n## Troubleshooting\n\n- If you get an error that looks like the following during obtaining a certificate, please check your firewall configuration, and ensure the ports for performing the challenge (HTTP: 80, TLS: 443, DNS: 53) are reachable from the outside world.\n\n```\nurn:ietf:params:acme:error:connection :: Timeout during connect (likely firewall problem), url: ...\n```\n\n- Dependency errors\n\nThe LEGO package imports various api clients for providing the DNS challenges - unfortunately this leads to frequent incompatibilities, in code that is not under our control.\nIn case this happens usually googling the error message is sufficient to find the go module replace directive that pins the needed version.\nPlease open an issue if you could not fix a dependency error on your own.\n\n- Container Pitfalls\n\nBe careful with containers that are configured to automatically restart on errors!\nWhen obtaining (or storing) a certificate fails for whatever reason, and your container will crash and restart automatically, you might get blocked due to the letsencrypt APIs rate limits. \n\nAnother common pitfall is to forget mounting the cache directory into your container, this way simplecert will obtain a new cert on every deployment, which will also likely cause rate limit issues after a while.\n\nYou can read more about the letsencrypt API rate limits here: https://letsencrypt.org/docs/rate-limits/\n\n## License\n\nMIT","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffoomo%2Fsimplecert","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffoomo%2Fsimplecert","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffoomo%2Fsimplecert/lists"}