Web app of the basimilch cooperative.
If you are new to Rails, you might want to take the time to read at least the official Getting Started with Rails guide. If you are interested in a more in-depth introduction to Ruby on Rails development you might want to look at the excellent Rails Tutorial by Michael Hartl including more than 15 hours of screencast lessons. The corresponding Rails Tutorial Book can be read online for free.
- Ruby Code (v2.5.1) (
ruby
releases) - Ruby 2.5.1 Core Documentation
- Ruby 2.5.1 Standard Library Documentation
- Ruby Style Guide
rvm
as the Ruby Version Manager (rvm
releases)
Beyond these official guides, it can be useful to read The Beginner's Guide to Rails Helpers.
curl -sSL https://get.rvm.io | bash -s stable
NOTE: If you already have installed it you can upgrade
rvm
withrvm get stable
.
rvm install 2.5.1
gem install bundler
- Go to the app directory and install the
gem
s defined in theGemfile.lock
withbundle
:
bundle install
-
rails
version 5.2.1 gets installed by the previous action. If you want to start a new project at this point you should manually installrails
instead:gem install rails -v 5.2.1
) -
heroku is used for the production server. To deploy, install the heroku toolbelt.
Setup dev environment on Cloud9
You can easily setup a development environment online at Cloud9
(aka c9.io
).
-
Create a new machine at
c9.io
-
Bootstrap the environment:
./config_c9io_machine.sh
If everything when well the DB should have been seeded with dummy data and the tests should have seen executed.
To run the rails server
on Cloud9
you have to provide the proper
IP and port running following command:
rails server -b $IP -p $PORT
As mentioned in the section 4.2 of the Rails Tutorial Book:
Our principal tool for learning Ruby will be the Rails console, a command-line program for interacting with Rails applications (...)
The Rails console can be started with rails console
(or rails c
for short).
As suggested in the aforementioned section, adding following
configuration in the ~/.irbrc
file will simplify the display of the
console:
cat << EOF >> ~/.irbrc
# SOURCE: https://www.railstutorial.org/book/rails_flavored_ruby#code-irbrc
IRB.conf[:PROMPT_MODE] = :SIMPLE
IRB.conf[:AUTO_INDENT_MODE] = false
EOF
The local Rails server can be started with:
$ rails server
The application expects a number of environment variables to configure
parameters like e.g. email addresses. You don't need to setup any
required environment variables by hand on your local dev machine.
Those values are automatically handled from the file .env
file by
the dotenv gem.
You can set up environment variables in Heroku on the web interface (i.e. https://dashboard.heroku.com/apps/basimilch-dev/settings) or with the heroku toolbelt:
$ heroku config:set RAILS_ENV=staging RACK_ENV=staging
Setting config vars and restarting example... done
RAILS_ENV: staging
RACK_ENV: staging
Further environment variables that are not required but you might want to set up, specially on heroku, include:
-
EMAIL_SMTP_USERNAME
-
EMAIL_SMTP_PASSWORD
-
EMAIL_SMTP_DOMAIN
-
EMAIL_SMTP_ADDRESS
-
EMAIL_SMTP_PORT
-
EMAIL_RECIPIENTS_WHITELIST
: If this ENV variable has a non-blank value, only addresses matching the comma-separated list of emails will be send emails to. See the fileconfig/initializers/mailer.rb
.
Note that those environment variables might have different values for staging and production servers.
In the Gemfile
here are two 'gem's that are very useful for
debugging the local application during development: byebug
and
web-console
.
Dropping a byebug
call anywhere in your code, will stop the program
and show a debug prompt in the process or terminal where the rails server
command is running. And in case you wonder why debugger
seems to do the same thing, it is indeed because debugger
is an
alias for byebug
.
In order to prevent forgetting the breakpoint in production we have
modified the helper byebug
(see Kernel
module in
rails_extensions.rb
) so that it will raise an error in the tests
to help finding the call before pushing to production.
Dropping a console
call in a controller or view, you get a ruby
console in the browser, as explained in the Usage Section of the
web-console
documentation:
The web console allows you to create an interactive Ruby session in your browser. Those sessions are launched automatically in case on an error, but they can also be launched manually in any page. For example, calling
console
in a view will display a console in the current page in the context of the view binding.<% console %>Calling
console
in a controller will result in a console in the context of the controller action:class PostsController < ApplicationController def new console @post = Post.new end end
In order to prevent forgetting the console in production (and to type
less) ;) we have provided the helper ApplicationHelper#c
, i.e. you
simply need to drop a c
in your code (e.g. in a controller) to see
a ruby
console in the corresponding view. Using
ApplicationHelper#c
will raise an error in the tests to help finding
the call before pushing to production.
For a good introduction about how to use the web-console
, you might
want to have a look at the ~5min video about how to use Web Console
in Rails 4.2.
We use the testing setup suggested in the Advanced testing setup
section of the Rails Tutorial Book mentioned above. This setup
includes color enhanced representation of test results (with
minitest
reporters), a backtrace silencer
configuration and the
usage of Guard
with guard-minitest
for automatic test
execution of file changes.
Once everything is set up as described in the mentioned section of the
Rails Tutorial Book, you can run Guard
at the command line as
follows:
$ bundle exec guard
The rules in the corresponding Guardfile
are seeded with the
content of Listing 3.42 of the Rails Tutorial Book. For example,
the integration tests automatically run when a controller is changed.
To run all the tests, hit return
at the guard>
prompt. As
mentioned in the Rails Tutorial Book, this may sometimes give an
error indicating a failure to connect to the Spring server. To fix the
problem, just hit return again. To exit Guard
, press Ctrl-D
.
The Rails Tutorial Book mentions also following hint:
The Spring server is still a little quirky as of this writing, and sometimes Spring processes will accumulate and slow performance of your tests. If your tests seem to be getting unusually sluggish, it’s thus a good idea to inspect the system processes and kill them if necessary.
This can be done with, e.g.:
$ ps aux | grep spring
$ pkill -9 -f spring
We use the brakeman
(v3.3.2) gem to detect security
vulnerabilities in the Ruby on Rails application via static analysis.
Used in conjunction to the guard-brakeman
gem, brakeman
is
automatically executed on files changes when running Guard
. This
means that when you execute the command bundle exec guard
suggested
above you will see both security vulnerability warnings and test
results after each file change.
NOTE: In some cases warnings might be false positives, but they should all be seriously taken into consideration.
At some point tests started to fails only on Travis-CI, but not
locally. It turned out that the problem occurred only on a clean test
DB (therefore on Travis-CI, because the environment is always re-
created from scratch). When executing rake test
the test DB is not
completely cleaned up before running the tests. Executing rake test:db
instead does clean up the DB before starting the tests, which
allowed the same error to be reproduced locally.
It turned out that the issue was related to how the fixtures where
loaded to the test DB. Some items where not able to be created because
the required associated models did not exists yet in the DB. And
therefore, running a second time rake test
worked without issues,
because the required associations were created in the previous run.
That pointed out to an error with the loading order of the fixtures. I was directly using numeric ids for the fixtures, and this prevented Rails to figure out the proper loading order. Instead of using numeric ids, I learned how to reference them by label (see links below for further details), which allows Rails to properly figure out the loading order of the fixtures.
Finally I had to update the tests to take into account the new ids of
the fixtures, and the tests now consistently pass also with rake test:db
.
For further details:
- ActiveRecord::FixtureSet
- Tricks and Tips for using Fixtures effectively in Rails
- unit testing - Rails fixtures -- how do you set foreign keys? - Stack Overflow
Also inspired by the Rails Tutorial Book, section 9.3.2, we use
the very funny Faker library 😂 to generate fake random data to
pre-populate the DB for dev purposes. This population is defined in
the file db/seeds.rb
. As recommended in this article about Rails
Migration Etiquette, to create a local DB usable for dev execute:
$ bundle exec rake db:setup
This command creates a clean database directly from the file
db/schema.rb
, which is maintained by Rails itself, (i.e. rake db:schema:load
), and then seeds it with the demo data in the file
db/seeds.rb
mentioned above (i.e. rake db:seed
). Doing so you
prevent running all migrations from scratch (done with rake db:migrate:reset
)
To start over with a new local dev DB execute:
$ bundle exec rake db:reset
This will automatically delete the previous local DB and proceed with
a db:setup
.
To start over with a clean local dev DB without seeding it execute following command, as inspired from this SO answer:
$ bundle exec rake db:drop db:create db:schema:load
If the db/schema.rb
is not in sync anymore with your migrations,
perform a migration after dropping and creating the database, instead
of directly loading the schema, which recreates the db/schema.rb
file:
$ bundle exec rake db:drop db:create db:migrate
To learn how to perform DB operations on heroku see Heroku > DB below.
The datamodel has evolved quite a lot during development. To simplify
things, we are merging all migrations into one initial null
migration before the first production launch. To prevent manual
errors, we are using a gem called squasher
.
However, merging migrations is not a good idea after the first production usage, or when several people are working on the same project.
By default Rails applications use an SQLite database, which has the advantage of being self-contained in a single file and thus being extremely easy to use and install (basically you don't have to do anything to have it working). However Heroku runs Rails apps with a PostgreSql database.
Although you can use SQLite in your local environment while letting Heroku runs your app with PostgreSql, it's generally highly recommended to use the same database (even the same version) in development as in production. This is also a good practice for [twelve-factor apps].
As of this writing, Heroku uses version 9.4.x of PostgreSql. You can
check which version is currently used for you app with heroku pg:info
:
$ heroku pg:info
=== DATABASE_URL
Plan: Hobby-dev
Status: Available
Connections: 0/20
PG Version: 9.4.3
Created: 2015-08-04 15:30 UTC
Data Size: 8.0 MB
Tables: 6
Rows: 1663/10000 (In compliance)
Heroku provides documentation to upgrade you PostgreSql version.
To use locally PostgreSql you might follow Heroku's own documentation
for the local setup of PostgreSQL or watch episode #342 of
Railcasts.com. In the case of MacOS X, the easiest way is to install
it using homebrew
. The main commands are:
brew search postgresql # To look for the version you need to install
brew install homebrew/versions/postgresql94 # Since we need version 9.4.x in out case
psql --version # Validate the installation and version
initdb /usr/local/var/postgres -E utf8 # create a database
As suggested by this Belyamani's article, to start the PostgreSql
database you can install the lunchy gem
as a helper:
gem install lunchy
cp /usr/local/Cellar/postgresql94/9.4.5/homebrew.mxcl.postgresql94.plist ~/Library/LaunchAgents/
lunchy start postgres
As mentioned in this SO answer, please note that lunchy
it will
not work inside of a tmux
session.
As a final step, create a new PostgreSql user basimilchdbuser
,
setup the database and run the tests:
createuser --superuser basimilchdbuser
bundle exec rake db:setup
bundle exec rake test
The .travis.yml
file should also be updated in order to let
Travis-CI properly perform the tests as explained in the Travis
documentation.
I recently had a problem with the PostgresSql DB on my computer (Mac OS X 10.10.5), which suddenly stopped working without supposedly having changed anything in the system. After a computer restart, the tests refused to start with following error:
$ bundle exec rake test
rake aborted!
PG::ConnectionBad: could not connect to server: No such file or directory
Is the server running locally and accepting
connections on Unix domain socket "/tmp/.s.PGSQL.5432"?
.../.rvm/gems/ruby-2.3.1/gems/activerecord-4.2.6/lib/active_record/connection_adapters/postgresql_adapter.rb:651:in `initialize'
I was not able to restart the DB and ended up creating a new one (not an issue since I had only test data that can be quickly re-seeded) following the steps from above, in summary:
mv /usr/local/var/postgres{,_bak} # to be able to start a new DB
sudo chown -R $(whoami) /usr/local # ensure you own /usr/local
initdb /usr/local/var/postgres -E utf8 # create a database
sleep 5 # wait a bit until DB is up
createuser --superuser basimilchdbuser # create a db user
bundle exec rake db:setup # bootstrap DB
bundle exec rake test # test everything
Note: I got the DB screwed up a couple of times after updating the
ownership of /usr/local
to fix a multi-user brew
setting.
The CI workflow is managed by travis-ci.org
. The file
.travis.yml
configures and orchestrates the behavior explained
below.
###Â Development - dev
branch
Each push to the dev
branch triggers a build on travis-ci.org
which will execute the tests. If the test suite passes, Travis-CI will
deploy the new code to the test app on Heroku, automatically applying
any DB migrations if necessary (with rake db:migrate
).
Note: To prevent a commit to trigger a build, add
[ci skip]
to the commit message as mentioned in the Travis-CI documentation.
###Â Production - master
branch
A similar thing occurs when pushing to the master
branch: if all
tests pass, the new code will be deployed to production. As an
additional step before deploying in this case, the production app
will be automatically set to maintenance mode and a backup of
the DB will be captured. After the deployment and eventual DB
migrations are successful, the app is automatically set back out of
maintenance mode.
Note: The setup for this automation is (as of March 2016) not straightforward to setup for Travis-CI. For future reference, I've created a gist with the steps I ended up doing to automatically set the Heroku app in maintenance mode and capturing a DB backup.
All displayed strings are entered in the localization file
de-CH.yml
. Although currently there is only one localization (i.e.
de-CH
), this has two main advantages:
- All displayed strings are gathered in one file which makes corrections and changes easy to manage.
- The work to add potential languages in the future (like e.g.
fr-CH
orit-CH
) is already prepared.
For localization we use the rails-i18n
gem, which provides many
common locale data.
The usual way to return a localized string is:
I18n.t 'store.title' # Lookup translation for the 'store.title' key
I18n.l Time.now # Localize Date and Time objects to local formats
Those are directly available in the views, without class name, e.g.:
<% provide(:title, t('users.index.title')) %>
As described in the "Lazy" Lookup section of the mentioned guide, if the following key hierarchy is defined in the dictionary:
de-CH:
users:
index:
title: "Alle Benutzer"
The value of users.index.title
inside the app/views/users/index.html.erb
view template can be looked up like this (note the dot):
<% provide(:title, t('.title')) %>
Variables can be interpolated in the localization string like so:
de-CH:
message: "Hoi %{name}!"
I18n.t :thanks, name: 'Jeremy'
For more details about how localization work you might refer to the
i18n
Rails guide.
There are lots of authentication libraries ready to use with Ruby on Rails. However in this application we based our implementation on the content of Chapter 10: "Account activation and password reset" of the Rails Tutorial Book by Michael Hartl.
Even Devise
, one on the most popular authentication libraries in
this context, recommends to follow the indications of the mentioned
chapter instead of using the library itself when beginning with Rails
in order to get used to it.
Our first implementation followed the traditional
username
/password
model described in the documentation mentioned
above. Very soon, though, we switched to a passwordless login workflow
which offers plenty of advantages for our use case. When a user
wants to log in the application, she requests a login code
to her
email address, which is immediately delivered. She can then log in by
either manually entering the code into the corresponding field in the
browser or by clicking on the code in the email itself. The login code
is only valid 5 minutes and has to be used in the same
computer and browser where it has been requested.
To validate the user postal addresses and IP addresses on singup we
use the geolocalization library Geocoder v1.3.7
. This library will
allow us also operations related to geographical relations between
users, depots and other entities.
We have configured the Geocoder gem
to use the Google Geocode API
with the :google
symbol. The official Usage Limits of the
Google Geocode API allow up to 2,500 free requests per day (and 10
requests per second). However, after releasing the app to Heroku, we
realized that the geolocation API was returning a quota exceeded
error even if we were far below the theoretical limits. As mentioned
in several
places, this seems related to the fact that
Google counts the usage against the requesting IP address. Thus in
PaaS environments like Heroku, public IPs used to perform such API
requests are frequently shared, leaving individual apps out of quota
quickly. One way to workaround this limitation is to use a service
like QuotaGuard. However, this service is too expensive for our
needs. Luckily, the Google Geocode API allows you to get an API
key for it (credit card needed), which allows to count the quota
against the key instead of the IP address.
We use the gem paper_trail
(v5.1.1) to audit changes on models.
This gem creates versions each time a model item changes by simply
adding has_paper_trail
to the model. It allows to inspect, compare
or revert to how things looked at a given point in time.
While following the installation documentation, we added the option
--with-changes
as mentioned in the diffing versions section. The
final installation commands were the following:
$ bundle exec rails generate paper_trail:install --with-changes
create db/migrate/20160111140705_create_versions.rb
create db/migrate/20160111140706_add_object_changes_to_versions.rb
$ bundle exec rake db:migrate
...
The option --with-changes
adds an additional column to the
Versions
table that allows to directly query the changes between
directly adjacent versions with the method .changeset
. E.g. to learn
what last changed in a user do:
User.find(42).update(first_name: "Bar")
# => true
User.find(42).update(first_name: "Foo")
# => true
User.find(42).versions.last.changeset
# => {"first_name"=>["Foo", "Bar"],
# "updated_at"=>[2016-01-11 14:13:30 UTC, 2016-01-11 14:13:44 UTC]}
Finally we also added two further columns request_remote_ip
and
request_user_agent
to the Versions
table to store metadata from
controllers in order to track from where the change was originated.
The population of this metadata is implemented in the file
/app/controllers/application_controller.rb
.
We use the gem public_activity
(v1.4.3)* to record activities in
the application.
* Note that the gem
version in Rubygems.org is v1.4.3
but the tag in github.com is
v1.4.1
.
Adding resources :users
to the config/routes.rb
file generates
all the actions needed for a RESTful Users resource, along with a
large number of named routes to generate user URLs. The resulting
correspondence of URLs, actions, and named routes is shown in following table:
HTTP request | URL | Action | Named route | Purpose |
---|---|---|---|---|
GET |
/users |
index |
users_path |
page to list all users |
GET |
/users/1 |
show |
user_path(user) |
page to show user |
GET |
/users/new |
new |
new_user_path |
page to make a new user (signup) |
POST |
/users |
create |
users_path |
create a new user |
GET |
/users/1/edit |
edit |
edit_user_path(user) |
page to edit user with id 1 |
PATCH |
/users/1 |
update |
user_path(user) |
update user |
DELETE |
/users/1 |
destroy |
user_path(user) |
delete user |
Source: Table 7.1. in Rails Tutorial Book
In Rails 2 & 3, the value of the session is stored in a cookie as a
base64
encoded serialized string with an added signature. Session
data is thus almost clear text (see Decoding Rails Session Cookies
for example about how to decode it).
However, in Rails 4 (which we are using), the value of the cookie is
an encrypted string. You have to have access to both the production
secret_key_base
and to the source code of the application so that
you can use the built-in infrastructure to decode the session as
explained in Session storage and security in Rails and demoed in
this gist.
For more info about security, read the Ruby on Rails Security Guide.
As a general reminder, cookies can only contain 4K of data for the entire cookie, including name, value, expiry date, etc.
Active Record provides a generator to handle the generation of migration files:
rails generate migration name_of_the_migration
Additionally, as stated in the RailsGuide about migrations:
If the migration name is of the form "AddXXXToYYY" or "RemoveXXXFromYYY" and is followed by a list of column names and types then a migration containing the appropriate add_column and remove_column statements will be created.
Note that this also works for snake_case
migration names as we use
it here: add_xxx_to_yyy
or remove_xxx_from_yyy
. The list of
column names and types mentioned in the quoted documentation text has
to be given in the following form: column_name:data_type
.
As an example, to remove columns there is a rails generate
operation
that will generate the expected migration:
$ rails generate migration remove_password_related_columns_from_users password_digest:string password_reset_digest:string password_reset_at:datetime password_reset_sent_at:datetime
invoke active_record
create db/migrate/20160103160340_remove_password_related_columns_from_users.rb
$ bundle exec rake db:migrate
== 20160103160340 RemovePasswordRelatedColumnsFromUsers: migrating ============
-- remove_column(:users, :password_digest, :string)
-> 0.0751s
-- remove_column(:users, :password_reset_digest, :string)
-> 0.0728s
-- remove_column(:users, :password_reset_at, :datetime)
-> 0.0680s
-- remove_column(:users, :password_reset_sent_at, :datetime)
-> 0.0746s
== 20160103160340 RemovePasswordRelatedColumnsFromUsers: migrated (0.2908s) ===
It might be also interesting to read this SO answer about creating simple vs compound indexed, as well as Heroku's own documentation about Efficient Use of PostgreSQL Indexes.
If the tests seems to fail for a weird reason, please make sure that
the test DB is in sync with the db/schema.rb
. As suggested in
"Maintaining The Test Database Schema", you have to execute
db:test:prepare
:
bundle exec db:test:prepare
In some places, this command is supposed deprecated (but worked for me 😕). They recommend to execute instead:
bundle exec rake db:migrate RAILS_ENV=test
Alternatively, if the db/schema.rb
is correct you can reload it to
the test
environment with:
bundle exec rake db:schema:load RAILS_ENV=test
Please make sure that neither the tests nor the rails console
are
running when applying migrations, since this can result in such
misalignments.
Another common cause of leaving the test DB in an inconsistent state
is when rollbacking a migration (during dev) with db:rollback
.
For a comprehensive description of all db:
rake tasks you can check
the code at railties/databases.rake
.
For a gut introduction to Active Record scopes
you might want to
read the article Advanced Active Record in Rails 4 | 9.1 Scopes.
We currently use following Heroku add-ons:
-
New Relic, which provides deep information about the performance of the web application as it runs in production. It requires the New Relic add-on and the
newrelic_rpm
gem. -
Sentry, which enables live error tracking to monitor and fix application crashes in real time. It requires the Sentry add-on and the
sentry-raven
gem.
As mentioned in the heroku documentation about the Timeout awaiting process:
The heroku run command opens a connection to Heroku on port 5000. If your local network or ISP is blocking port 5000, or you are experiencing a connectivity issue, you will see an error similar to:
$ heroku run rails console Running rails console attached to terminal... Timeout awaiting process
In the logs this error appears as Error R13 (Attach error) -> Failed to attach to process
. If you cannot fix the problem (e.g. opening port
5000
), some tasks can be performed in a detached
mode as a
workaround:
$ heroku run:detached rake db:migrate
Running rake db:migrate... up, run.2
Use 'heroku logs -p run.2' to view the log output.
But not all command can be executed in a background way: e.g.
heroku run rails console
makes no sense in a detached context.
To start with a fresh dev DB on Heroku do following commands:
heroku pg:reset --app basimilch-dev DATABASE
heroku run rake db:migrate
heroku run rake db:seed
To create a user with your email address, start a rails console on heroku (heroku run rails console
) an run following command:
User.new(first_name: "your_first_name", last_name: "your_last_name", email: "your_email@example.com", admin: true, activation_sent_at: Time.current).save(validate: false)
The following examples are the main heroku
commands related to the management
of the Postgres database. Please refer to the official
Heroku documentation about Postgres DB backups
for more details and further commands.
Every night at 3:00am a backup of the production database is automatically created. To schedule automatic backups run the following command:
heroku pg:backups:schedule DATABASE_URL --at '03:00 Europe/Zurich' --app basimilch
To verify the scheduled backups run the following command:
heroku pg:backups:schedules --app basimilch
Please note that when the database plan is changed or the database instance is modified the backup schedule might be lost. Please verify the expected backup schedule in such cases.
(Link to relevant Heroku documentation)
heroku pg:backups capture --app basimilch-dev
(Link to relevant Heroku documentation)
heroku pg:backups restore --app basimilch-dev
(Link to relevant Heroku documentation)
Having real data on the dev DB might be useful to check that everything works as expected before deploying to production, specially before big or non-trivial migrations. To copy the last backup from the prod DB to the dev DB on heroku do following commands:
Note that we start doing a backup of the dev DB, which might be optional, depending on your needs.
heroku pg:backups capture --app basimilch-dev
heroku pg:backups restore $(heroku pg:backups public-url --app basimilch) DATABASE_URL --app basimilch-dev
To learn more about this procedure and about the
heroku pg:backups restore
commands visit the
Heroku documentation page
and this StackOverflow thread.
Please refer to the Heroku documentation about pg:push
and
pg:pull
to learn about how to get a copy of the DB from dev
or
prod
to your local machine (or the other way around):
pg:pull
can be used to pull remote data from a Heroku Postgres database to a database on your local machine. The command looks like this:$ heroku pg:pull HEROKU_POSTGRESQL_MAGENTA mylocaldb --app sushi
Like pull but in reverse,
pg:push
will push data from a local database into a remote Heroku Postgres database. The command looks like this:$ heroku pg:push mylocaldb HEROKU_POSTGRESQL_MAGENTA --app sushi
For reference, the first prod
DB was imported locally from the
previously used spreadsheet and pg:push
ed into production.
We are using an SSL certificate from Let's encrypt to secure communications between the browser and the application. The exact instructions about creating and installing the certificate were followed from this Medium article and Heroku's own documentation about SSL. As explained in both articles, for that we had to add the non-free Heroku SSL addon.
###Â Certificate renewal
The free certificates from Let's encrypt are valid (as of now) for
only 3 months. The certificate for meine.basimil.ch
can be
renewed form the Cloud9
IDE with the following steps from the
Let's encrypt documentation:
./letsencrypt-auto renew --manual-public-ip-logging-ok
Note that letsencrypt-auto
is the official "Let’s Encrypt" client,
but the other several lets-encrypt
clients available.
To verify the certificate, the corresponding domain needs to serve a challenge string on a secret URL provided in the output of the command above, e.g.:
-------------------------------------------------------------------------------
Processing /etc/letsencrypt/renewal/meine.basimil.ch.conf
-------------------------------------------------------------------------------
Make sure your web server displays the following content at
http://meine.basimil.ch/.well-known/acme-challenge/wheQaqVGXFyWh6c6-8PtX-pMJxyl6YE before continuing:
wheQaqVGXFyWh6c6-8PtX-pMJxyl6YE._vNsdaf0TA_jMgfijgFq3xasa9xIFyNfdijf2U
(...)
Press ENTER to continue
To serve that file, you have to set up the ENV
variable
LETSENCRYPT_CHALLENGE
with the value filename,challenge
. For the
example output above, that would be:
heroku config:add --app basimilch LETSENCRYPT_CHALLENGE=wheQaqVGXFyWh6c6-8PtX-pMJxyl6YE,wheQaqVGXFyWh6c6-8PtX-pMJxyl6YE._vNsdaf0TA_jMgfijgFq3xasa9xIFyNfdijf2U
After the app has been restarted on Heroku, verify that the expected
challenge is returned at the requested URL, e.g. in that case
http://meine.basimil.ch/.well-known/acme-challenge/wheQaqVGXFyWh6c6 -8PtX-pMJxyl6YE
,
and proceed with the renewal command by pressing ENTER
.
Once the certificate has successfully been renewed, the corresponding files must be updated on Heroku:
heroku certs:update --app basimilch /etc/letsencrypt/live/meine.basimil.ch/fullchain.pem /etc/letsencrypt/live/meine.basimil.ch/privkey.pem
You will be asked to confirm. To proceed, type basimilch
.
Note that it might take up to five minutes until you actually see that the certificates have been updated.
To verify that everything has gone as expected, you might list the certificates of the app with following command:
heroku certs:info --app basimilch