How can I deploy a secure (HTTPS) Meteor app on Heroku? - ssl

I would like to deploy my Meteor app to Heroku and make it only accessible through HTTPS. Ideally, I want to do this as cheaply as possible.

Create the Certificate
Run these commands to get certbot-auto. certbot-auto should work on most systems
wget https://dl.eff.org/certbot-auto
chmod 755 certbot-auto
This command starts the process of getting your certificate. The -d flag allows you to pass in the domain you would like to secure. Alternatively, without the -d flag, it will pop up a prompt where you can enter the domain.
./certbot-auto certonly --manual -d app.yoursite.com
Then it will ask you the following. Do not hit enter.
Make sure your web server displays the following content at
http://app.yoursite.com/.well-known/acme-challenge/SOME-LENGTHY-KEY before continuing:
SOME-LONGER-KEY
Use Picker
I suggest using this method because on renewal, you will only need to update an environment variable. You can use public/ as below, but it will require a rebuild of your entire app every time
Run meteor add meteorhacks:picker
In a server side file, add the following
import { Picker } from 'meteor/meteorhacks:picker';
Picker.route('/.well-known/acme-challenge/:routeKey', (params, request, response) => {
response.writeHead('200', {'Content-Type': 'text/plain'});
response.write(process.env.SSL_PAGE_KEY)
response.end();
});
Then set an environment variable SSL_PAGE_KEY to SOME-LONGER-KEY with
heroku config:set SSL_PAGE_KEY=SOME-LONGER-KEY
Use public/
Create the directory path in your public folder. If you don't have one, create one.
mkdir -p public/.well-known/acme-challenge/
Then create the file SOME-LENGTHY-KEY and place SOME-LONGER-KEY inside it
echo SOME-LONGER-KEY > public/.well-known/acme-challenge/SOME-LENGTHY-KEY
Commit and push that change to your Heroku app.
git push heroku master
Now hit enter to continue the verification process. You should receive a message like this
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at
/etc/letsencrypt/live/app.yoursite.com/fullchain.pem. Your cert will
expire on 2016-04-11. To obtain a new version of the certificate in
the future, simply run Let's Encrypt again.
Upload the Certificate
To upload your certificates to Heroku, first enable the SSL Beta
heroku labs:enable http-sni -a your-app
heroku plugins:install heroku-certs
Then add your fullchain.pem and privkey.pem to Heroku.
sudo heroku _certs:add /etc/letsencrypt/live/app.yoursite.com/fullchain.pem /etc/letsencrypt/live/app.yoursite.com/privkey.pem
You can verify that the certificate was uploaded with
heroku _certs:info
Change your DNS Settings
Update your DNS to point to app.yoursite.com.herokudns.com
Verify SSL is working
To check that SSL is set up, run the following. -v gives you verbose output. -I shows the document info only. -H passes a header to the URL. The header we're passing ensures that a cache is not being used and will ensure you get your new certificate and not an old one.
curl -vI https://app.yoursite.com -H "Cache-Control: no-cache"
Check that the output contains the following
* Server certificate:
* subject: C=US; ST=CA; L=SF; O=SFDC; OU=Heroku; CN=app.yoursite.com
If the subject line does not contain CN=app.yoursite.com, wait 5 to 10 minutes and try again. If it does, you're almost good to go.
Make Meteor Specific Changes
To finish up the process, you'll want to change your ROOT_URL environment variable to the new https version.
heroku config:set ROOT_URL=https://app.yoursite.com
Then you'll want to ensure that your users are always using SSL with the force-ssl package
meteor add force-ssl
Lastly, if you have any OAuth logins set up in your app (Facebook, Google, etc), you'll want to provide them with the new https version of your URL.
Renewal
Run certbot-auto again
./certbot-auto certonly --manual -d app.yoursite.com
It may prompt you for the same endpoint with the same content. If it does, just hit enter. If it does not, you will need to repeat the above steps.
It will then create new certificate files, which you will upload to Heroku with
heroku certs:update /etc/letsencrypt/live/app.yoursite.com/fullchain.pem /etc/letsencrypt/live/app.yoursite.com/privkey.pem
Then to confirm, run the Verify SSL is working commands above
Sources
https://certbot.eff.org/#ubuntutrusty-other
https://devcenter.heroku.com/articles/ssl-beta
https://themeteorchef.com/blog/securing-meteor-applications/

Related

Certbot unable to find AWS credentials when issuing certificate via dns for route53

I need to get an certificate for my domain hosted on AWS Route 53 from LetsEncrypt. I do not have any port 80 or 443 exposed since the server is used for VPN and does not have a public access.
So the only way to do this is via DNS validation of route 53.
So far I have installed certbot and dns-route53 plugin
sudo snap install --beta --classic certbot
sudo snap set certbot trust-plugin-with-root=ok
sudo snap install --beta certbot-dns-route53
sudo snap connect certbot:plugin certbot-dns-route53
I have created a special user in my AWS account who has access to Route53 and I have added the access key id and secret access key in the ~/.aws/config and also ~/.aws/credentials which looks something like this
[default]
aws_access_key_id=foo
aws_secret_access_key=bar
Basically followed every step given here: https://certbot-dns-route53.readthedocs.io/en/stable/
Now when I run the following command:
sudo certbot certonly -d mydomain.com --dns-route53
It gives the following output:
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator dns-route53, Installer None
Requesting a certificate for mydomain.com
Performing the following challenges:
dns-01 challenge for mydomain.com
Cleaning up challenges
Unable to locate credentials
To use certbot-dns-route53, configure credentials as described at https://boto3.readthedocs.io/en/latest/guide/configuration.html#best-practices-for-configuring-credentials and add the necessary permissions for Route53 access.
I went to the documentation given in the error message: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/configuration.html#best-practices-for-configuring-credentials
but I do not think there is anything wrong I am doing
I even went to the root level by doing sudo su and exported the AWS keys as env vars there and even exported the AWS keys in the home as well but it still throws me the same error.
so I also ran into this same issue, and it's likely because of you running certbot with sudo, when do you do that, whatever user you've used as ~/, is ignored, as instead, it's looking in /root/.
I fixed it by (centos) is my user where I have the .aws/ directory with config and credential files.
sudo -s
ln -s /home/centos/.aws/ ~/.aws
ls -lsa ~/.aws
... /root/.aws -> /home/centos/.aws/

Nginx not taking into account renewed let's encrypt certificates

I have a server running some NodeJs apps (MeteorJs to be precise) on internal ports. I use Nginx to proxy_pass requests that are targeting URLs to the apps.
Let's say app_1 is running on localhost:3000, I would proxy_pass app1.domain.com to localhost:3000 and then add firewall rule to restrict access on port 3000.
Then I add SSL on the incoming connection for app1.domain.com using letsencrypt. I generate certs using certbot certonly -w /var/www/app1 -d app1.domain.com and then set the nginx config file to use it.
Everything works flawlessly until it's time to renew the cert.
To do the renewal, I have the following cron job :
12 6 * * 3 /root/renew.sh
with the following script /root/renew.sh :
certbot renew
service nginx reload
The problem I have is that upon expiration, the nginx webserver is not serving the new certificate !
So I added the following cron job :
30 6 * * 3 service nginx restart
but it still fails to refresh the certificate (which leads to error in navigators, saying connexion is not secure because of cert expiration). So I need to manually log in and reload nginx.
What is wrong in my setup ?
Thanks
You can set everything in one cronjob line (modified basic setup):
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
0 */12 * * * root test -x /usr/bin/certbot -a \! -d /run/systemd/system && perl -e 'sleep int(rand(43200))' && certbot -q renew --deploy-hook "nginx -t && systemctl restart nginx"
This cron job is triggered twice every day to check if certificate is getting expired in next 30 days or not. It shouldn't cause performance problems.
If it is getting expired then it will auto renew it quietly without generating output and restart NGINX to apply changes. If certificate is not getting expired then it will not perform any action.
Be aware --deploy-hook argument was added in certbot version 0.17, released in July 2017
After more testing, here is the answer to this issue:
Set the cron job to point to a bash script:
12 6 * * 3 /root/renew.sh
And set the bash script like this:
certbot renew
sleep 1m
service nginx reload
Note the presence of the sleep command which allows to wait until the renewal is done

How to install Zimbra certification?

I have this error when I want install a commercial SSL in Zimbra
Your certificate was not installed due to the error : system failure:
exception executing command: zmcertmgr verifycrtkey comm
/opt/zimbra/mailboxd/webapps/zimbraAdmin/tmp/current_comm.key
/opt/zimbra/mailboxd/webapps/zimbraAdmin/tmp/current.crt with
{RemoteManager: mail.mydomain.com->zimbra#mail.mydomain.com:22}
Use below script for SSL install in Zimbra.
#!/bin/bash -x
# SSL certificate installation in Zimbra
# with SSL certificate provided by Let's Encrypt (letsencrypt.org)
# Author: Subhash (serverkaka.com)
# Check if running as root
if [ "$(id -u)" != "0" ]; then
echo "This script must be run as root" 1>&2
exit 1
fi
read -p 'letsencrypt_email [xx#xx.xx]: ' letsencrypt_email
read -p 'mail_server_url [xx.xx.xx]: ' mail_server_url
# Check All variable have a value
if [ -z $mail_server_url ] || [ -z $letsencrypt_email ]
then
echo run script again please insert all value. do not miss any value
else
# Installation start
# Stop the jetty or nginx service at Zimbra level
su - zimbra -c 'zmproxyctl stop'
su - zimbra -c 'zmmailboxdctl stop'
# Install git and letsencrypt
cd /opt/
apt-get install git
git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt
# Get SSL certificate
./letsencrypt-auto certonly --standalone --non-interactive --agree-tos --email $letsencrypt_email -d $mail_server_url --hsts
cd /etc/letsencrypt/live/$mail_server_url
cat <<EOF >>chain.pem
-----BEGIN CERTIFICATE-----
MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow
PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD
Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O
rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq
OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b
xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw
7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD
aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG
SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69
ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr
AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz
R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5
JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo
Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
-----END CERTIFICATE-----
EOF
# Verify commercial certificate
mkdir /opt/zimbra/ssl/letsencrypt
cp /etc/letsencrypt/live/$mail_server_url/* /opt/zimbra/ssl/letsencrypt/
chown zimbra:zimbra /opt/zimbra/ssl/letsencrypt/*
ls -la /opt/zimbra/ssl/letsencrypt/
su - zimbra -c 'cd /opt/zimbra/ssl/letsencrypt/ && /opt/zimbra/bin/zmcertmgr verifycrt comm privkey.pem cert.pem chain.pem'
# Deploy the new Let's Encrypt SSL certificate
cp -a /opt/zimbra/ssl/zimbra /opt/zimbra/ssl/zimbra.$(date "+%Y%m%d")
cp /opt/zimbra/ssl/letsencrypt/privkey.pem /opt/zimbra/ssl/zimbra/commercial/commercial.key
sudo chown zimbra:zimbra /opt/zimbra/ssl/zimbra/commercial/commercial.key
su - zimbra -c 'cd /opt/zimbra/ssl/letsencrypt/ && /opt/zimbra/bin/zmcertmgr deploycrt comm cert.pem chain.pem'
# Restart Zimbra
su - zimbra -c 'zmcontrol restart'
# setting auto https redirect
cd /opt && touch https-redirect.sh && chown zimbra:zimbra https-redirect.sh && chmod +x https-redirect.sh
cat <<EOF >>/opt/https-redirect.sh
zmprov ms $mail_server_url zimbraReverseProxyMailMode redirect
EOF
su - zimbra -c '/opt/https-redirect.sh'
rm /opt/https-redirect.sh
fi
For more reference check this link: https://github.com/SubhashPatel/Install-Zimbra-mail-server-ubuntu/blob/master/configure-ssl-zimbra.sh
You should try using CLI to install SSL certificate for Zimbra. Also you need to verify that you have the same certificate which you have downloaded from the certificate authority.
For commercial.crt you need to copy one certificate downloaded from the authority. For commercial_ca.crt, there must be one CA bundle file, you will have from certificate authority.
Private key, you need to verify during generating your CSR and also verify with the hosting. After that restart the Zimbra by command
zmcontrol restart
finally i found the solution.
you shouldn't fill the subject alternative name when you want create csr!
thats all.
Every other year I spend hours on renewing the ssl certificates on zimbra with the help of hopeless outdated tutorials. A tedious process that I don't do often enough to remember how I did it. I learned the hard way that it is easier to use the admin console, than using CLI and messing around with concatinating the different certificates.
Hereby the steps that I take:
Please note that this is a walkthrough, dedicated to the
GoGetSSL Sectigo PositiveSSL Wildcard certificate, and may not work for other SSL providers.
Zimbra version: 8.8.15
We use the wildcard certificate on several servers, but we generate the CSR always(!) on the zimbra server. So go to admin console > Configure > Certificates, click the domain in the list and then in top right corner, choose install certificate. Choose the generate CSR option (second of the 3 options). Make sure that in the common name field you use the wildcard symbol: e.g.
*.example.com
Also check the checkbox that it concerns a wildcard common name
Fill out the rest of the info according to your situation. At the bottom, there's option to add other names; remove all of them (if any). Go to next page and download the CSR, finish the wizard.
on the GoGetSSL page create the new/renew the SSL certificate with the by Zimbra generated CSR. Finish up the entire process, including the validation. All the way up to that the certificate is issued and files can be downloaded. Choose to download the 'All files' zip file. extract on your local system.
browse to: https://www.gogetssl.com/wiki/intermediate-certificates/sectigo-intermediate-root-certificates/
On this page download the file: DV RSA Files > RSA DV Bundle with SHA-1 (TXT file)
go back to admin console > Configure > Certificates, click the domain in the list and then in top right corner, choose install certificate. This time you choose the 3rd option: install commercial signed certificate. First screen of the wizard shows the info you entered earlier for the CSR. The info may show up empty. For me this didn't give me any problems, so I left it. On the next screen: You have to upload 3 certificate files by default, but we need to upload 4, so we need to do Add Intermediate CA for the fourth file.
Choose files as follows:
Certificate: server certificate from the zip file: e.g. _example.com.crt
Root CA: RSA DV Bundle with SHA-1 (TXT file), from the link above
Intermediate CA: USERTrust_RSA_Certification_Authority.crt from zip file
(Added) Intermediate CA: AAA_Certificate_Services.crt
NOTE: I can't remember which Intermediate CA I chose first, so if any problems, try switching the last 2 mentioned files around.
Finish the wizard and test by sending and receiving email.
Then I take the certificates and update other servers with these certificates. (e.g. nginx, apache2, etc). Note: you may need to get the commercial.key file for use on other servers. On linux this file is located in: /opt/zimbra/ssl/zimbra/commercial/
If permission denied, you may use root account or do: sudo su - zimbra
I hope this helps for people struggling with the same certificate and zimbra

How to solve a challenge to authorize my domain for letsencrypt?

I'm trying to authorize my domain for letsencrypt. Previously, a few months ago on a different server, I didn't it, now I do for some reason.
./letsencrypt-auto certonly -a webroot --webroot-path=/home/deployer/pfios -d my_website.com -d www.my_website.com
Failed authorization procedure. my_website.com (http-01): urn:acme:error:unauthorized :: The client lacks sufficient authorization :: The key authorization file from the server did not match this challenge [fdsfs-fdsfdsf.fdsfdsfds333] != [gangnam style!]
Domain: www.my_website.com
Type: unauthorized
Detail: The key authorization file from the server did not match
this challenge
[fdsfs-fdsfdsf.fdsfdsfds333]
!= [gangnam style!]
The code for authorization or rather the name of a file is different each time. Where should I actually retrieve it? In this case it's "fdsfs-fdsfdsf.fdsfdsfds"
Try authorize your domain via standalone webserver from LE.
./letsencrypt-auto certonly -a standalone -d my_website.com -d www.my_website.com
You must remember - when you generate new cert you must off your main webserver (Apache, nginx, etc.)
In my case solved it by running
sudo apt-get update and then running the renew command
/usr/bin/letsencrypt renew
Check if you have IPV6 redirection configured in your DNS provider.
If the redirection does not redirect to your server, remove it.

Docker: What is the simplest way to secure a private registry?

Our Docker images ship closed sources, we need to store them somewhere safe, using own private docker registry.
We search the simplest way to deploy a private docker registry with a simple authentication layer.
I found :
this manual way http://www.activestate.com/blog/2014/01/deploying-your-own-private-docker-registry
and the shipyard/docker-private-registry docker image based on stackbrew/registry and adding basic auth via Nginx - https://github.com/shipyard/docker-private-registry
I think use shipyard/docker-private-registry, but is there one another best way?
I'm still learning how to run and use Docker, consider this an idea:
# Run the registry on the server, allow only localhost connection
docker run -p 127.0.0.1:5000:5000 registry
# On the client, setup ssh tunneling
ssh -N -L 5000:localhost:5000 user#server
The registry is then accessible at localhost:5000, authentication is done through ssh that you probably already know and use.
Sources:
https://blog.codecentric.de/en/2014/02/docker-registry-run-private-docker-image-repository/
https://docs.docker.com/userguide/dockerlinks/
You can also use an Nginx front-end with a Basic Auth and an SSL certificate.
Regarding the SSL certificate I have tried couple of hours to have a working self-signed certificate but Docker wasn't able to work with the registry. To solve this I have a free signed certificate which work perfectly. (I have used StartSSL but there are others).
Also be careful when generating the certificate. If you want to have the registry running at the URL registry.damienroch.com, you must give this URL with the sub-domain otherwise it's not going to work.
You can perform all this setup using Docker and my nginx-proxy image (See the README on Github: https://github.com/zedtux/nginx-proxy).
This means that in the case you have installed nginx using the distribution package manager, you will replace it by a containerised nginx.
Place your certificate (.crt and .key files) on your server in a folder (I'm using /etc/docker/nginx/ssl/ and the certificate names are private-registry.crt and private-registry.key)
Generate a .htpasswd file and upload it on your server (I'm using /etc/docker/nginx/htpasswd/ and the filename is accounts.htpasswd)
Create a folder where the images will be stored (I'm using /etc/docker/registry/)
Using docker run my nginx-proxy image
Run the docker registry with some environment variable that nginx-proxy will use to configure itself.
Here is an example of the commands to run for the previous steps:
sudo docker run -d --name nginx -p 80:80 -p 443:443 -v /etc/docker/nginx/ssl/:/etc/nginx/ssl/ -v /var/run/docker.sock:/tmp/docker.sock -v /etc/docker/nginx/htpasswd/:/etc/nginx/htpasswd/ zedtux/nginx-proxy:latest
sudo docker run -d --name registry -e VIRTUAL_HOST=registry.damienroch.com -e MAX_UPLOAD_SIZE=0 -e SSL_FILENAME=private-registry -e HTPASSWD_FILENAME=accounts -e DOCKER_REGISTRY=true -v /etc/docker/registry/data/:/tmp/registry registry
The first line starts nginx and the second one the registry. It's important to do it in this order.
When both are up and running you should be able to login with:
docker login https://registry.damienroch.com
I have create an almost ready to use but certainly ready to function setup for running a docker-registry: https://github.com/kwk/docker-registry-setup .
Maybe it helps.
Everything (Registry, Auth server, and LDAP server) is running in containers which makes parts replacable as soon as you're ready to. The setup is fully configured to make it easy to get started. There're even demo certificates for HTTPs but they should be replaced at some point.
If you don't want LDAP authentication but simple static authentication you can disable it in auth/config/config.yml and put in your own combination of usernames and hashed passwords.