I'm using http-server to serve my local project through HTTPS. To create the key.pem and the cert.pem files, I followed the documentation:
First, you need to make sure that openssl is installed correctly, and
you have key.pem and cert.pem files. You can generate them using this
command:
openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem
You will be prompted with a few questions after
entering the command. Use 127.0.0.1 as value for "Common name" if you
want to be able to install the certificate in your OS's root
certificate store or browser so that it is trusted.
This generates a cert-key pair and it will be valid for 3650 days
(about 10 years).
Then you need to run the server with -S for enabling SSL and -C for
your certificate file.
http-server -S -C cert.pem
I used the openssl.exe come with the Git, and installed the generated certificate on Windows (onto the "Trusted Root Certification Authorities" entry). Here is the output after running the server:
Starting up http-server, serving ./ through https
http-server version: 14.1.1
http-server settings:
CORS: disabled
Cache: 3600 seconds
Connection Timeout: 120 seconds
Directory Listings: visible
AutoIndex: visible
Serve GZIP Files: false
Serve Brotli Files: false
Default File Extension: none
Available on:
https://10.20.30.232:8080
https://192.168.56.1:8080
https://192.168.1.126:8080
https://127.0.0.1:8080
Hit CTRL-C to stop the server
But, when I access the https://127.0.0.1:8080, I'm encountered with the following error on Google Chrome:
Your connection is not private
...
NET::ERR_CERT_COMMON_NAME_INVALID
Subject: 127.0.0.1
Issuer: 127.0.0.1
...
This server could not prove that it is 127.0.0.1; its security certificate does not specify Subject Alternative Names.
And, the following is the error message Mozilla Firefox presents:
127.0.0.1:8080 uses an invalid security certificate.
The certificate does not come from a trusted source.
Error code: MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY
https://127.0.0.1:8080/
The server uses a certificate with a basic constraints extension identifying it
as a certificate authority. For a properly-issued certificate, this should not
be the case.
HTTP Strict Transport Security: false
HTTP Public Key Pinning: false
So, what am I missing on setting up the HTTPS server to avoid the aforementioned errors?!
Chrome should accept this certificate if you explicitly list 127.0.0.1 as a "Subject Alternative Name" (SAN) of type IP. You can do so by adding -addext "subjectAltName = IP:127.0.0.1" to the openssl command:
openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem -addext "subjectAltName = IP:127.0.0.1"
Firefox complains about a very different issue, i.e. that a certificate with a basic constraints extension with CA:TRUE is being used as an end-entity certificate. See also: https://bugzilla.mozilla.org/show_bug.cgi?id=1034124
You could try to generate the certificate without the basic constraints extenstion.
The shortcut solution would be to leverage existing solutions like https://github.com/FiloSottile/mkcert or https://github.com/davewasmer/devcert.
I've set up a redbird based proxy following its README file examples.
By now I've configured single domain both for http and https and it's working well (https still using self-signed certificate).
But now I'm trying to configure it to use letsencrypt to automatically get valid ssl certificates and I'm getting stuck in following error:
{"level":30,"time":1578681102208,"pid":21320,"hostname":"nigul","name":"redbird","0":false,"1":"setChallenge called for 'exposito.bitifet.net'","msg":"Lets encrypt debugger","v":1}
[acme-v2] handled(?) rejection as errback:
Error: Error: Failed HTTP-01 Pre-Flight / Dry Run.
curl 'http://exposito.bitifet.net/.well-known/acme-challenge/test-cf55199519d859042f695e620cca8dbb-0'
Expected: 'test-cf55199519d859042f695e620cca8dbb-0.MgLl7GIS59DPtPMejuUcXfddzNt8YxfLVo5op670u8M'
Got: '<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>404 - Not Found</title>
</head>
<body>
<h1>404 - Not Found</h1>
</body>
</html>
'
See https://git.coolaj86.com/coolaj86/acme-v2.js/issues/4
at /home/joanmi/SERVICES/redbird_domains/node_modules/acme-v2/index.js:49:10
at process._tickCallback (internal/process/next_tick.js:68:7)
As far as I understand, this is telling me that Lets Encrypt is trying to access to the url http://exposito.bitifet.net/.well-known/acme-challenge/test-cf55199519d859042f695e620cca8dbb-0 using the following command:
curl 'http://exposito.bitifet.net/.well-known/acme-challenge/test-cf55199519d859042f695e620cca8dbb-0'
...and that it is getting which seems a 404 HTML Error page which I have no clue wherever it could come.
And, in fact, executing that curl command or just pasting that url in my browser (you can try it: I left the server running), I get the given Expected string so, from my point of view it seems like if my configuration were correct but, for some reason, Lets Encrypt's servers were reaching another server (either because of wrong routing or DNS).
But on the other hand, I suppose it's more probable that I've done something wrong in my configuration.
Here I paste my whole script (ports 80 and 443 are redirected to 1080 and 1443, respectively, through iptables because the script is run by non privileged user):
const Redbird = require("redbird");
const proxy = Redbird({
port: 1080,
xfwd: false, // Disable the X-Forwarded-For header
letsencrypt: {
path: __dirname + '/certs',
port: 9999
// LetsEncrypt minimal web server port for handling challenges.
// Routed 80->9999, no need to open 9999 in firewall. Default 3000
// if not defined.
},
ssl: {
http2: true,
port: 1443, // SSL port used to serve registered https routes with LetsEncrypt certificate.
}
});
proxy.register('exposito.bitifet.net:9999', 'http://localhost:8001', {
ssl: {
letsencrypt: {
email: 'xxxxxx#gmail.com', // Domain owner/admin email
production: false,
// WARNING: Only use this flag when the proxy is verified to
// work correctly to avoid being banned!
}
}
});
proxy.register("exposito.bitifet.net", "http://localhost:8001");
Any clue will be welcome.
Thanks.
SOLVED!!
Many issues were involved at the same time (despite my lack of experience with either redbird and letsencrypt.
The magic 404/Not found page: I guess it came from a lighttpd server that seems to had been preinstalled in my VPS.
Port 80 was redirected via iptables but I suppose in one or other configuration tweak I could have redirected incoming requests to localhost's port 80 (which is not redirected).
My redbird missunderstanding: Looking at examples in its README file, I thought redbird were kinda "multi- reverse_proxy" in the sense that you could redirect http and https requests with single redbird instance.
But I finally realized that the (maybe not so well named) port option which is, in fact, an http port, serves only to configure a built-in unconditional http->https redirector (of which I already had read about, but I thought it were optional).
The actual underlying issue: If your DNS have DNSSEC activated, you should define a CAA register in it pointing to letsencrypt.org.
At the moment I disabled DNSSEC instead because my provider's control panel doesn't allow me to create such register.
I discovered it while trying to get the certificates through certbot (sudo apt-get install certbot which I must say that, If I had known about it before, I wouldn't had care about trying redbird's letsencrypt integration.
It is much more verbose (while redbird is more like a black box when errors arise) and pointed out that I needed the CAA register.
Here the notes I took about it (in case anyone could be interested):
Free SSL Certificates with Certbot
Install certbot:
sudo apt-get install certbot
Create:
sudo certbot certonly --manual --preferred-challenges http -d <domain>
Renew:
sudo certbot renew
Caveats:
DNSSEC
If your DNS server has DNSSEC enabled, you will need to add a CAA
register pointing to letsencrypt.org.
...and your DNS provider my not allow to create it (at least I
couldn't with CDMON. Also not -yet- complained).
production = false is for other kinds of testing: I read that if you put in to true while testing, you may be banned from letsencrypt if you perform too many requests.
Setting it to false you can test redirections, but you will see still errors regarding letsencrypt even you could navigate without a secure certificate (I think kinda self-signed is provided to allow testing). So don't expect a valid one.
ssl port is used for redirection: Not a (big) issue, but if you specify ssl port other than 443, built in redirector will unconditionally redirect you to that port.
Running redbird as root and using standard (80 and 443) ports works fine. But if you, like me, want to use an alternative ports in order to execute redbird with non privileged user, you will get redirected to that alternative port instead of 443 (Even having it redirected through iptables).
Here my (almost*) final redbird script:
const Redbird = require("redbird");
const proxy = Redbird({
port: 1080,
xfwd: false, // Disable the X-Forwarded-For header
ssl: {
port: 1443,
},
letsencrypt: {
path: __dirname + '/certs',
port: 9999,
// LetsEncrypt minimal web server port for handling challenges.
// Routed 80->9999, no need to open 9999 in firewall. Default 3000
// if not defined.
},
});
proxy.register('exposito.bitifet.net', 'http://exposito.bitifet.net:8001', {
ssl: {
http2: true,
letsencrypt: {
email: 'xxxxxx#gmail.com', // Domain owner/admin email
production: true,
// WARNING: Only use this flag when the proxy is verified to
// work correctly to avoid being banned!
},
}
});
(*) I still need to fix the explicit-port redirection issue (5), because I don't want to run redbird as root. But I know is possible to allow uses to listen given ports. Even I would probably better try to patch redbird in order to allow specifying listen and redirection ports separatedly.
EDIT: It is already implemented (and documented) using the (optional) option redirectPort in ssl section. Just added redirectPort: 443 and job done!!
EDIT 2: For the sake of completion, there still was another issue I struggled with.
To get things working I finally configured the redirection to the http port instead of https one.
That is: Incomming https requests gets redirected to my application http port.
It seems weird but it works. At least if you don't need any exclusively https feature such as push notifications (which I plan to use in the future).
But its implies to open an http server at least on localhost. Which isn't a major issue now (this is only a playground server) but I plan to use redbird at work to proxy multiple domains to different servers so that would had forced us to open http at least in our DMZ vlan (which is an additional risk that is better to avoid...).
When I tried redirecting to https I got the DEPTH_ZERO_SELF_SIGNED_CERT error.
Ok: This is telling me that redbird (or node) does not trust my original (self signed) certificate. I know there is an option to tell node to accept those certificates. But maybe it is not the way to go...
So I configured my application to use the same certificate that redbird is obtaining through letsencrypt.
But then I got this other error:
UNABLE_TO_VERIFY_LEAF_SIGNATURE
Researching a bit I found this StackOverflow answer that explains how to get all root and intermediate certificates trusted by Mozilla and make node to trust them.
So, at the end, what I did was:
Installed node_extra_ca_certs_mozilla_bundle package:
npm install --save node_extra_ca_certs_mozilla_bundle
Prepended NODE_EXTRA_CA_CERTS=node_modules/node_extra_ca_certs_mozilla_bundle/ca_bundle/ca_intermediate_root_bundle.pem to the start command in the package.json's scripts section.
Updated my redbird script to point again to the https (protocol and) port:
proxy.register('exposito.bitifet.net', 'https://localhost:4301', {...]);
Here my final redbird configuration:
const Redbird = require("redbird");
const proxy = Redbird({
port: 1080,
xfwd: false, // Disable the X-Forwarded-For header
ssl: {
port: 1443,
redirectPort: 443
// key: "/etc/bitifet/exposito/ssl/private.key",
// cert: "/etc/bitifet/exposito/ssl/public.cert",
},
letsencrypt: {
path: __dirname + '/certs',
port: 9999,
// LetsEncrypt minimal web server port for handling challenges.
// Routed 80->9999, no need to open 9999 in firewall. Default 3000
// if not defined.
},
});
proxy.register('exposito.bitifet.net', 'https://localhost:4301', {
ssl: {
http2: true,
letsencrypt: {
email: 'xxxxxx#gmail.com', // Domain owner/admin email
production: true,
// WARNING: Only use this flag when the proxy is verified to
// work correctly to avoid being banned!
},
}
});
And here my package.json file contents:
{
"name": "redbird_domains",
"version": "0.0.1",
"description": "Local Domains Handling",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "NODE_EXTRA_CA_CERTS=node_modules/node_extra_ca_certs_mozilla_bundle/ca_bundle/ca_intermediate_root_bundle.pem node ./index.js"
},
"author": "Joanmi",
"license": "GPL-3.0",
"dependencies": {
"node_extra_ca_certs_mozilla_bundle": "^1.0.4",
"redbird": "^0.10.0"
}
}
Has anyone made Laravel Valet (secure) work nicely with Browser Sync while using Laravel Mix. I am doing something like this but it keeps pointing me to https://shadow-api.test:3000 where as I simply want to omit the port.
mix.browserSync({
proxy: 'shadow-api.test',
host: 'shadow-api.test',
open: 'external',
https: {
key: "/Users/aligajani/.config/valet/Certificates/shadow-api.test.key",
cert: "/Users/aligajani/.config/valet/Certificates/shadow-api.test.crt"
}
});
For your information, I am using the latest versions of everything, fresh install and intend on building a SPA (with token auth). I haven't had similar issues with BrowserSync before simply because I wasn't using Valet.
Better late than never.. this works for me:
.browserSync({
proxy: 'https://mass-importer.faaren.test',
host: 'mass-importer.faaren.test',
open: 'external',
https: {
key: "/Users/fabianhagen/.config/valet/Certificates/mass-importer.faaren.test.key",
cert: "/Users/fabianhagen/.config/valet/Certificates/mass-importer.faaren.test.crt"
}
});
I had to prefix the proxy domain with https://. It still opens under port 3000 (or another if this port is already used), but browsersync is working.
I’m using ubuntu 18.04.1 LTS with docker / docker compose and traefik. The setup to get certificates is working fine using the staging Let’s Encrypt caserver (https://acme-staging-v02.api.letsencrypt.org/directory). All my specified hosts do get a Fake LE Intermediate X1cert. There are no errors in the logs.
I can however not enable Let’s Encrypt production certs.
In the traefik.toml file - [acme] I deleted the staging caserver uri: no error in the logs / no production cert (staging cert is still applied). Even when I add the Let’s Encrypt prod uri (https://acme-v02.api.letsencrypt.org/directory 2) although it should default, result is sill the same: no prod certs and acme.json still shows the staging uri.
The traefik [acme]:
[acme]
email = "someone#gmail.com"
caserver = "https://acme-v02.api.letsencrypt.org/directory 2"
storage="acme.json"
entryPoint = "https"
onHostRule = true
[acme.httpChallenge]
entryPoint = "http"
[[acme.domains]]
main = "mydomain"
[[acme.domains]]
…
What am I missing? Appreciate your input.
Issue is solved.
Delete the acme.json & recreate the file. Initially I deleted the content of the acme file but that did not work as explained earlier.
Delete the staging domain:
certbot delete --cert-name example.com
And then retrieve another certificate.
I had the same question. On a server I had issued a cert for 16 domains using the Let's Encrypt staging server using:
sudo certbot --test-cert --apache -d example.com -d www.example.com
To switch over to Let's Encrypts production I ran:
sudo certbot --force-renewal --apache -d example.com -d www.example.com
force-renewal did the trick. But don't run this to many times as you risk hitting LE's rate limit.
I've been setting up couchdb to run on SSL following the instructions from couch docs. Its pretty straight forward, you make 3 adjustments to local.ini:
httpsd = {chttpd, start_link, [https]}
cert_file = absolute/path/to/cert.pem
key_file = absolute/path/to/key.pem
I've made the key and certificate with openssl no problem, but whenever I ping port 6984 on the localhost (the port its supposed to run on by default) I just get a non active port:
==> curl https://127.0.0.1:6984/
curl: (7) Failed to connect to 127.0.0.1 port 6984: Connection refused
I've inspected the port, nothing is running there. I can put a node.js server on the port and it works fine too. I can't find a similar situation to this anywhere. I'm running the mac OSX couchdb application (v 2.1.2). It appears that the ssl server daemon is just straight up not running at all. Everything else in couch is working fine. Maybe I have to tweak the local.ini file to turn the daemon on? No idea really. Any suggestions are appreciated.
Not sure if this will ever be a very popular question but just thought I'd point out that a very popular way to set up SSL with couchdb is to use a proxy like haproxy due to annoyances with ssl and erlang (which couchdb is written in).
That being said, I solved my problem by setting up SSL termination at haproxy that then forwards traffic to couchdb on an internal port. For use on a mac OSX machine the steps were pretty easy.
1) Install haproxy with brew brew install haproxy
2) Create a self signed certificate with openssl that haproxy needs for ssl configuration (it's really just a concatenated file of your key and certificate):
openssl genrsa -out key.key 1024
openssl req -new -key key.key -out cert.csr
openssl x509 -req -days 365 -in cert.csr -signkey key.key -out certificate.crt
cat ./certificate.crt ./key.key | tee combined.pem
3) create haproxy configuration file (haproxy.cfg), this is just a pretty naive first implementation, but is a good starting point. Note that "/absolute/path/to/combined.pem" would be changed to wherever the combined.pem file is actually located.
global
maxconn 512
spread-checks 5
defaults
mode http
log global
monitor-uri /_haproxy_health_check
option log-health-checks
option httplog
balance roundrobin
option forwardfor
option redispatch
retries 4
option http-server-close
timeout client 150000
timeout server 3600000
timeout connect 500
stats enable
stats uri /_haproxy_stats
# stats auth admin:admin # Uncomment for basic auth
frontend http-in
# bind *:$HAPROXY_PORT
bind *:443 ssl crt /absolute/path/to/combined.pem no-tls-tickets ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-GCM-SHA384:AES128-SHA256:AES128-SHA:AES256-SHA256:AES256-SHA:!MD5:!aNULL:!DH:!RC4
#Add these lines beneath bind, still within http-in
reqadd X-Forwarded-Proto:\ https
# Distinguish between secure and insecure requests
acl secure dst_port eq 8000
# Mark all cookies as secure if sent over SSL
rsprep ^Set-Cookie:\ (.*) Set-Cookie:\ \1;\ Secure if secure
# Add the HSTS header with a 1 year max-age
rspadd Strict-Transport-Security:\ max-age=31536000 if secure
# Redirect HTTP to HTTPS
redirect scheme https code 301 if !{ ssl_fc }
default_backend couchdbs
backend couchdbs
option httpchk GET /_up
http-check disable-on-404
server couchdb1 127.0.0.1:5984 check inter 5s
4) Run couchdb, run haproxy via changing directory to the directory housing the above haproxy.cfg file and running with that configuration: haproxy -f haproxy.cfg.
This is a simple point to start from. This set up can handle load balancing of multiple couchdbs, and in production would need a valid certificate from some authority. For anyone interested in, or having difficulty with ssl and couchdb in a mac OSX development environment, this is a decent solution that I found to work quite nicely.