forked from TryGhost/Ghost-CLI
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refs TryGhost#64 - add nginx service - add ssl provisioning via greenlock-cli
- Loading branch information
Showing
5 changed files
with
195 additions
and
1 deletion.
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
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,45 @@ | ||
server { | ||
listen 80; | ||
listen [::]:80; | ||
|
||
server_name <%= url %>; | ||
|
||
<% if (ssl) { %> | ||
location / { | ||
return 301 https://$server_name$request_uri; | ||
} | ||
|
||
location ~ /.well-known { | ||
allow all; | ||
} | ||
<% } else { %> | ||
root <%= root %>; | ||
|
||
location / { | ||
proxy_set_header X-Real-IP $remote_addr; | ||
proxy_set_header Host $http_host; | ||
proxy_pass http://127.0.0.1:<%= port %>; | ||
} | ||
<% } %> | ||
} | ||
|
||
<% if (ssl) { %> | ||
server { | ||
listen 443 ssl http2; | ||
listen [::]:443 ssl http2; | ||
|
||
# SSL Configuration snippets | ||
include snippets/ssl-<%= url %>.conf; | ||
include snippets/ssl-params.conf; | ||
|
||
root <%= root %>; | ||
|
||
location / { | ||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | ||
proxy_set_header X-Forwarded-Proto $scheme; | ||
proxy_set_header X-Real-IP $remote_addr; | ||
proxy_set_header Host $http_host; | ||
proxy_pass http://127.0.0.1:<%= port %>; | ||
} | ||
} | ||
<% } %> |
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,2 @@ | ||
ssl_certificate /etc/letsencrypt/live/<%= url %>/fullchain.pem; | ||
ssl_certificate_key /etc/letsencrypt/live/<%= url %>/privkey.pem; |
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,21 @@ | ||
# from https://cipherli.st/ | ||
# and https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html | ||
|
||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; | ||
ssl_prefer_server_ciphers on; | ||
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH"; | ||
ssl_ecdh_curve secp384r1; | ||
ssl_session_cache shared:SSL:10m; | ||
ssl_session_tickets off; | ||
ssl_stapling on; | ||
ssl_stapling_verify on; | ||
resolver 8.8.8.8 8.8.4.4 valid=300s; | ||
resolver_timeout 5s; | ||
# Disable preloading HSTS for now. You can use the commented out header line that includes | ||
# the "preload" directive if you understand the implications. | ||
#add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload"; | ||
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains"; | ||
add_header X-Frame-Options DENY; | ||
add_header X-Content-Type-Options nosniff; | ||
|
||
ssl_dhparam /etc/ssl/certs/dhparam.pem; |
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,125 @@ | ||
'use strict'; | ||
const fs = require('fs-extra'); | ||
const url = require('url'); | ||
const path = require('path'); | ||
const execa = require('execa'); | ||
const template = require('lodash/template'); | ||
const validator = require('validator'); | ||
|
||
const BaseService = require('../base'); | ||
|
||
class NginxService extends BaseService { | ||
init() { | ||
this.on('setup', 'setup'); | ||
} | ||
|
||
get parsedUrl() { | ||
return url.parse(this.config.get('url')); | ||
} | ||
|
||
setup(context) { | ||
if (!context.nginx) { | ||
return; | ||
} | ||
|
||
if (this.parsedUrl.port) { | ||
this.ui.log('Your url contains a port. Skipping automatic nginx setup.', 'yellow'); | ||
return; | ||
} | ||
|
||
if (this.parsedUrl.pathname !== '/') { | ||
this.ui.log('The Nginx service does not support subdirectory configurations yet. Skipping automatic nginx setup.', 'yellow'); | ||
return; | ||
} | ||
|
||
let prompts = [{ | ||
type: 'confirm', | ||
name: 'ssl', | ||
message: 'Do you want to set up your blog with SSL (using letsencrypt)?', | ||
default: true | ||
}, { | ||
type: 'input', | ||
name: 'email', | ||
message: 'Enter your email (used for ssl registration)', | ||
when: ans => ans.ssl, | ||
validate: email => validator.isEmail(email) || 'Invalid email' | ||
}]; | ||
|
||
if (this.config.environment === 'development') { | ||
prompts.splice(1, 0, { | ||
type: 'confirm', | ||
name: 'staging', | ||
message: 'You are running in development mode. Would you like to use letsencrypt\'s' + | ||
' staging servers instead of the production servers?', | ||
default: true, | ||
when: ans => ans.ssl | ||
}); | ||
} | ||
|
||
let answers; | ||
|
||
return this.ui.prompt(prompts).then((_answers) => { | ||
answers = _answers; | ||
|
||
fs.ensureDirSync(path.join(process.cwd(), 'root')); | ||
|
||
let conf = template(fs.readFileSync(path.join(__dirname, 'files', 'site.conf.template'), 'utf8')); | ||
let confFile = `${this.parsedUrl.hostname}.conf`; | ||
|
||
fs.writeFileSync(path.join(process.cwd(), confFile), conf({ | ||
ssl: answers.ssl, | ||
root: path.join(process.cwd(), 'root'), | ||
url: this.parsedUrl.hostname, | ||
port: this.config.get('server.port') | ||
})); | ||
|
||
return this.ui.noSpin(execa.shell(`sudo mv ${confFile} /etc/nginx/sites-available && ` + | ||
`sudo ln -s /etc/nginx/sites-available/${confFile} /etc/nginx/sites-enabled && ` + | ||
'sudo service nginx restart', {stdio: 'inherit'})); | ||
}).then(() => { | ||
if (!answers.ssl) { | ||
return; | ||
} | ||
|
||
return this._ssl(answers); | ||
}); | ||
} | ||
|
||
_ssl(options) { | ||
let letsencrypt = path.resolve(__dirname, '../../../node_modules/.bin/letsencrypt') | ||
let command = `sudo ${letsencrypt} certonly --agree-tos --email ${options.email} --webroot ` + | ||
`--webroot-path ${path.join(process.cwd(), 'root')} --config-dir /etc/letsencrypt ` + | ||
`--domains ${this.parsedUrl.hostname}`; | ||
|
||
if (options.staging) { | ||
// Use LetsEncrypt's staging server | ||
command += ' --server https://acme-staging.api.letsencrypt.org/directory'; | ||
} | ||
|
||
return this.ui.noSpin(execa.shell(command, {stdio: 'inherit'})).then(() => { | ||
if (fs.existsSync('/etc/nginx/snippets/ssl-params.conf')) { | ||
return; | ||
} | ||
|
||
return this.ui.noSpin(execa.shell( | ||
`sudo mv ${path.join(__dirname, 'files', 'ssl-params.conf')} /etc/nginx/snippets`, | ||
{stdio: 'inherit'} | ||
)); | ||
}).then(() => { | ||
let sslConf = template(fs.readFileSync(path.join(__dirname, 'files', 'ssl-cert.conf.template'), 'utf8')); | ||
let sslConfFile = `ssl-${this.parsedUrl.hostname}.conf`; | ||
|
||
fs.writeFileSync(path.join(process.cwd(), sslConfFile), sslConf({ | ||
url: this.parsedUrl.hostname | ||
})); | ||
|
||
return this.ui.noSpin(execa.shell(`sudo mv ${sslConfFile} /etc/nginx/snippets && ` + | ||
'sudo service nginx restart')); | ||
}); | ||
} | ||
} | ||
|
||
module.exports = { | ||
name: 'nginx', | ||
class: NginxService | ||
}; |