Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
193 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,37 @@ | ||
# cf-letsencrypt | ||
Let's Encrypt wrapper for Cloud-Foundry | ||
|
||
Create certificates for your Cloud-Foundry-hosted apps and domains using [Let's Encrypt](https://letsencrypt.org). | ||
|
||
Using the `--path` argument of the map-route command, you can specify just a path to be directed to a separate app. | ||
|
||
``` | ||
NAME: | ||
map-route - Add a url route to an app | ||
USAGE: | ||
cf map-route APP_NAME DOMAIN [--hostname HOSTNAME] [--path PATH] | ||
EXAMPLES: | ||
cf map-route my-app example.com # example.com | ||
cf map-route my-app example.com --hostname myhost # myhost.example.com | ||
cf map-route my-app example.com --hostname myhost --path foo # myhost.example.com/foo | ||
OPTIONS: | ||
--hostname, -n Hostname for the route (required for shared domains) | ||
--path Path for the route | ||
``` | ||
|
||
Firstly you must have your cf cli configured, domains created, and DNS configured to point to your CF provider. | ||
|
||
Once you have that, just edit the domains.yml file checked out from this repo and run `python setup-app.py`. | ||
|
||
This will push the app, map all the routes for the auto-check that LetsEncrypt needs to do to verify that you own the domain. | ||
It maps host.domain/.well-known/acme-challenge to this app for each domain/host that you want to generate a certificate for. | ||
|
||
The LetsEncrypt client will sign the requests, go through the verification and fetch the signed certificates that you can then fetch with the cf files command. | ||
|
||
Just watch the logs to see when the process has finished. `cf logs letsencrypt` | ||
|
||
While you could leave the app running, it probably makes sense to stop it when you don't need it, and just start it up when you need to renew certificates or add another host/domain. | ||
By default it will keep running for 1 week, then kill itself. DEA will then try to restart it for you... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
{ | ||
"email": "ben@example.com", | ||
"staging": false, | ||
"domains": [ | ||
{ | ||
"domain": "example.com", | ||
"hosts": [ | ||
".", | ||
"auth", | ||
"test", | ||
"www" | ||
] | ||
}, | ||
{ | ||
"domain": "example2.com", | ||
"hosts": [ | ||
"abc", | ||
"test" | ||
] | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
<html> | ||
<head><title>This is not here</title></head> | ||
<body> | ||
<h1>Hello!</h1> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
<html> | ||
<head><title>This is not here</title></head> | ||
<body> | ||
<h1>Hello!</h1> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
<html> | ||
<head><title>This is not here</title></head> | ||
<body> | ||
<h1>Hello!</h1> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
applications: | ||
- name: letsencrypt | ||
buildpack: python_buildpack | ||
memory: 64M | ||
instances: 1 | ||
no-hostname: true | ||
no-route: true | ||
path: . | ||
command: python run.py |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
cffi >= 0.8.0 | ||
letsencrypt >= 0.3.0 | ||
six>=1.7 | ||
pyyaml>=3.11 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import yaml | ||
import os | ||
import time | ||
import threading | ||
import SimpleHTTPServer | ||
import SocketServer | ||
from letsencrypt import cli | ||
|
||
cwd = os.getcwd() | ||
logs = cwd+"/logs" | ||
conf = cwd+"/conf" | ||
work = cwd+"/work" | ||
host = cwd+"/host" | ||
|
||
port = int(os.getenv('VCAP_APP_PORT', '5000')) | ||
|
||
# Before we switch directories, set up our args using the domains.yml settings file. | ||
with open('domains.yml') as data_file: | ||
settings = yaml.safe_load(data_file) | ||
|
||
print settings | ||
|
||
# Format commands | ||
args = ["certonly", "--non-interactive", "--text", "--debug", "--agree-tos", "--logs-dir", logs, "--work-dir", work, "--config-dir", conf, "--webroot", "-w", host] | ||
|
||
# Are we testing - i.e. getting certs from staging? | ||
if 'staging' in settings and settings['staging'] is True: | ||
args.append("--staging") | ||
|
||
args.append("--email") | ||
args.append(settings['email']) | ||
|
||
for entry in settings['domains']: | ||
domain = entry['domain'] | ||
for host in entry['hosts']: | ||
args.append("-d") | ||
if host == '.': | ||
fqdn = domain | ||
else: | ||
fqdn = host + '.' + domain | ||
args.append(fqdn) | ||
|
||
print "Args: ", args | ||
|
||
os.chdir('host') | ||
|
||
Handler = SimpleHTTPServer.SimpleHTTPRequestHandler | ||
httpd = SocketServer.TCPServer(("", port), Handler) | ||
|
||
# Start a thread with the server | ||
server_thread = threading.Thread(target=httpd.serve_forever) | ||
|
||
# Exit the server thread when the main thread terminates | ||
server_thread.daemon = True | ||
server_thread.start() | ||
print "Server loop listening on port ", port, ". Running in thread: ", server_thread.name | ||
|
||
print "Starting Let's Encrypt process in 1 minute..." | ||
|
||
time.sleep(60) | ||
|
||
print "Calling letsencrypt..." | ||
|
||
cli.main(args) | ||
|
||
print "Done." | ||
print "Fetch the certs and logs via cf files ..." | ||
print "You can get them with these commands: " | ||
print "cf files letsencrypt app/conf/live/" + settings['domains'][0]['domain'] + "/cert.pem" | ||
print "cf files letsencrypt app/conf/live/" + settings['domains'][0]['domain'] + "/chain.pem" | ||
print "cf files letsencrypt app/conf/live/" + settings['domains'][0]['domain'] + "/fullchain.pem" | ||
print "cf files letsencrypt app/conf/live/" + settings['domains'][0]['domain'] + "/privkey.pem" | ||
print "REMEMBER TO STOP THE SERVER WITH cf stop letsencrypt" | ||
|
||
# Sleep for a week | ||
time.sleep(604800) | ||
|
||
print "Done. Killing server..." | ||
|
||
# If we kill the server and end, the DEA should restart us and we'll try to get certificates again | ||
httpd.shutdown() | ||
httpd.server_close() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import yaml | ||
from subprocess import call | ||
|
||
with open('domains.yml') as data_file: | ||
settings = yaml.safe_load(data_file) | ||
|
||
print settings | ||
|
||
# Push the app, but don't start it yet | ||
call(["cf", "push", "--no-start"]) | ||
|
||
# For each domain, map a route for the specific letsencrypt check path '/.well-known/acme-challenge/' | ||
for entry in settings['domains']: | ||
domain = entry['domain'] | ||
for host in entry['hosts']: | ||
if host == '.': | ||
call(["cf", "map-route", "letsencrypt", domain, "--path", "/.well-known/acme-challenge/"]) | ||
else: | ||
call(["cf", "map-route", "letsencrypt", domain, "--hostname", host, "--path", "/.well-known/acme-challenge/"]) | ||
|
||
# Now the app can be started | ||
call(["cf", "start", "letsencrypt"]) |