
Show HN: I made a script to generate self-signed SSL certs for local development - kingkool68
https://github.com/kingkool68/generate-ssl-certs-for-local-development
======
moviuro
See [https://shellcheck.net](https://shellcheck.net) to fix your script and
follow good guidelines. Top of my head:

* /bin/bash -> /usr/bin/env bash

* You probably don't need bash anyway, so switch to /bin/sh

* errors go to stderr (>&2), not stdout

* exits because of errors should return non-zero codes. (e.g.: `exit 1`)

* Full caps variables are bad practise (might conflict with real, global env variables)

* rather than running everything as root (using sudo), I'd call sudo for the only few commands that actually require root privileges (I found none, so I suppose "security" is the only command that needs root perms).

~~~
RossM
Thank you for sharing this; I infrequently have to write standalone shell
scripts but every time I do I spend a while looking around for best practices
and often just end up with some contradicting opinions.

~~~
m0nty
There's also this:
[https://news.ycombinator.com/item?id=6866085](https://news.ycombinator.com/item?id=6866085)

And the Google 'Shell Style Guide':
[https://google.github.io/styleguide/shell.xml](https://google.github.io/styleguide/shell.xml)

Just in case you hadn't seen them already.

~~~
moviuro
Just for the record, the Google guide focuses on Google infrastructure and
systems, not portability. Using /bin/bash for instance is not a good idea if
you want to port your work to BSD systems.

~~~
stephenr
Bash isn't even a good choice if you want to support just macOS and Linux,
because the versions available are so wildly different.

~~~
jsjohnst
1) supporting both macOS and Linux in bash is trivial. Just stick to Bash 3
functionality.

2) Bash4 is trivial to install on macOS via home brew, so saying “available”
is a misnomer. “Default” would be a bit better, but many Linux distros still
in use don’t use Bash4.

3) Bash 3 vs 4 isn’t “wildly” different.

------
tialaramex
Although these will "work" today in popular browsers and with most tools, this
is NOT the right way to scribble a DNS name into a certificate this century.

Write SANs. Subject Alternative Names. These aren't aliases, the "alternative"
means in the sense that this is an "alternative" to writing human readable
X.500 series Common Names. Unlike those human names, SANs are defined in a
machine readable way, e.g. the dnsNAme SAN spells exactly DNS A-labels, the
ipAddress SAN is just an IPv4 or IPv6 address written out as raw bytes, not a
dotted decimal or whatever else someone thought might be fun today.

You should also write one of the SANs you choose as the Common Name in some
plausible text format, but by having SANs all vaguely modern tools can just
match those rather than trying to make sense of the Common Name.

In a very new OpenSSL you can actually do this from the command line sort-of
sensibly. In most installs you will need to modify that configuration file
instead, you're already using a configuration file so that's no big deal.

~~~
FiloSottile
This is important.

Chrome finally stopped looking at the Common Name field, and I'm hoping to
fade out support in the next few versions of Go. You can already test your
systems in 1.11 with GODEBUG=x509ignoreCN=1. Use SANs.

This was one of the motives to create mkcert:
[https://github.com/FiloSottile/mkcert](https://github.com/FiloSottile/mkcert)

------
FiloSottile
Good ideas are rarely unique, as they usually solve a common problem. I
recently built something similar:

[https://github.com/FiloSottile/mkcert](https://github.com/FiloSottile/mkcert)

It's in pure Go instead of using OpenSSL, and it works with Windows, macOS and
Firefox, too.

~~~
andy_ppp
Fascinating that Golang reimplemented all the crypto/ssl/tls in Golang itself
rather than linking to a C library. I'd probably trust the Go code (a safer
language) over OpenSSL so that's a pretty interesting use case.

~~~
beatgammit
Why? Surely OpenSSL has a bigger team auditing the codebase, especially
recently since they've gotten so much attention for previous security
failures.

Also, Go's TLS library is missing some important features, like decrypting
most varieties of private keys.

I use Go's TLS library, but I don't think it's necessary "better" than
openssl, though it's certainly more convenient.

~~~
andy_ppp
I'm making no definitive statements just more interested that they did it. I
would personally trust a new Go codebase over an old C codebase but I could
definitely be wrong in this case.

------
tombrossman
Also see "Certificates for localhost" from Certbot/Let's Encrypt
documentation:

[https://letsencrypt.org/docs/certificates-for-
localhost/](https://letsencrypt.org/docs/certificates-for-localhost/)

------
shivekkhurana
Your solution generates a certificate and leaves it up to the user to setup
https.

There are other steps involved, like adding the cert to the trust store (so
you don't get invalid SSL warnings). And also changing your application code
to use these certificates.

Even if you do that, you are still exposed to a serious security threat: if a
bad actor gets hold of your certificate file, they can pose as a legitimate
website and steal sensitive data. This security flaw is present with all other
script solutions mentioned in this thread.

To overcome these issues, I have built a mac application called HTTPSLocalhost
([https://httpslocalhost.com](https://httpslocalhost.com)).

\- It offers a user interface to add remove local https domains

\- Has an inbuilt proxy so you don't need to change your application code

\- Is much safer because it deletes the certificate and private keys as soon
as the proxy server starts

\- It creates a new certificate each time you start the app, to enhance
security.

\- And of course, like all good things, is free (there is a video demo on the
website, the app will be ready soon).

Wanted to do a proper Show HN next week, but I guess it's the right time to
bring it up :)

Thanks

~~~
Novashi
>Even if you do that, you are still exposed to a serious security threat: if a
bad actor gets hold of your certificate file, they can pose as a legitimate
website and steal sensitive data. This security flaw is present with all other
script solutions mentioned in this thread.

Sorry, but, what? Who is using self-signed certs for public production
websites?

~~~
shivekkhurana
Nobody uses self-signed certs on prod.

But if an attacker has a private key that is trusted by your local trust
store, they can pose a legitimate website (man in the middle) and decrypt your
traffic.

The title tells me that this thread is about local https. Nothing to do with
prod.

~~~
Novashi
I thought there were varying amounts of trust with certificate stores?

Local dev certs should go into a personal store or something that is less
trusted than something like VeriSign. You shouldn't be able to mint a legit-
looking Google certificates with the same private key that's only trusted via
a local self-signed certificate.

Maybe I don't understand something.

~~~
shivekkhurana
Couldn't mint absolutely legitimate certificates, but legitimate enough to
fool the browser and the person who is browsing.

------
NotANaN
_" Generating the certs is a complicated hassle."_

Not really... I will grant that the openssl commands are a bit non-obvious.

Step 1: Generate private key

openssl ecparam -genkey -name secp384r1 -out key.pem

Step 2: Create and sign cert

openssl req -x509 -sha512 -nodes -days 365 -key key.pem -subj
"/CN=example.com" -reqexts SAN -extensions SAN -config <(cat
/etc/ssl/openssl.cnf <(printf
'[SAN]\nsubjectAltName=DNS:example.com,DNS:*.example.com')) -out cert.pem

------
qubyte
I built something similar (though probably a lot less sophisticated) as an
alpine based docker image. I had some issues with openssl on a Mac in the
past, and this approach circumvents those.

[https://hub.docker.com/r/qubyte/cert-
creator/](https://hub.docker.com/r/qubyte/cert-creator/)

~~~
kingkool68
Nice! I dig it.

------
TekMol
I would use it if I could do so with PHP's internal webserver.

I often hack together quick experiments using PHP's internal webserver. It
only serves via http though, not https. Is there a way to make it serve over
https?

~~~
krab
There is a neat tool ncat that can work as a SSL server. If you run php on
port 8080 like this:

    
    
        $ php -S localhost:8080
    

Then, you can proxy with combination of ncat server and client:

    
    
        $ sudo ncat --listen --ssl localhost 443 -k --sh-exec "ncat localhost 8080"
    

You can also point ncat to your SSL certificate.

~~~
TekMol
Wow, this is cool!

I just tried it and it works nicely.

Thank you so much!

------
jlgaddis
If you have OpenSSL installed, you may also have a copy of the two decades old
shell script, "CA", that still works wonderfully today.

~~~
kevin_thibedeau
CA.pl is decidedly clunky. It really needs a rewrite.

------
kevin_thibedeau
> openssl genrsa -des3 ...

It's really time to lay DES to rest.

------
jfyne
[https://github.com/square/certstrap](https://github.com/square/certstrap)

------
nailer
If you prefer using macOS itself, making a trusted self signed cert only
requires a few clicks and one command [https://certsimple.com/blog/localhost-
ssl-fix](https://certsimple.com/blog/localhost-ssl-fix)

~~~
kingkool68
There are certainly many ways to do this.

------
algorithm_dk
check out the mkcert project, it's awesome and can be automated so everyone in
the team gets their own certs and CA

------
sigjuice
I have been using a Let's Encrypt wildcard certificate.

~~~
chupasaurus
Happy for your choice of DNS host which supports DNS verification.

~~~
icedchai
I run my own DNS servers, like I have for 20+ years. Not a problem.

