How we should configure action cable in Rails to work in Google App Engine?
I have a Rails application which is using action cable for its messenger.
On my local-host the action cable working well in development and production environments but its not working on Google App Engine.
I have created a Computer Engine instance and installed Redis on it.
Firewall allows all traffic to Redis VM.
Redis has bind 0.0.0.0
When I deploy the app on Google App Engine I get the error:
Firefox can’t establish a connection to the server at wss://mydomain.com/cable.
here is my current configuration:
config/environments/production.rb
config.action_cable.url = 'wss://[MYDOMAIN].com/cable'
config.action_cable.disable_request_forgery_protection = true
config.force_ssl = true
...
config/cable.yml
production:
adapter: redis
url: redis://[IP_OF_REDIS_SERVER]:6379/
app.yaml
entrypoint: bundle exec rackup --port $PORT
env: flex
runtime: ruby
env_variables:
REDIS_PROVIDER: REDIS_URL
REDIS_URL: redis://[IP_OF_REDIS_SERVER]:6379/
SECRET_KEY_BASE: [My_Secret_Key]
I couldn't find anything about actioncable setting in Google documentation of App Engine. I hope this question can help me and everyone with same issue.
You must set create a VPC between your Redis instance and you App Engine instance. This is documented here:
https://cloud.google.com/appengine/docs/standard/python/connecting-vpc
Once you've done this, you'll have:
app.yaml
...
vpc_access_connector:
name: projects/PROJECT_ID/locations/REGION/connectors/CONNECTOR_NAME
...
Secondly, the Google managed Redis server does not allow you to set a client id. I tried forcing it to be nil, but the ActionCable subscription adapter will try to set one for you:
https://github.com/rails/rails/blob/6-0-stable/actioncable/lib/action_cable/subscription_adapter/redis.rb#L18
In order to get it working properly, I had to override this behavior.
I added the following file into my rails app:
config/initializers/decorators/redis.rb
require 'action_cable/subscription_adapter/redis'
ActionCable::SubscriptionAdapter::Redis.class_eval do
cattr_accessor :redis_connector, default: ->(config) do
::Redis.new(config.except(:id, :adapter, :channel_prefix))
end
end
Now everything is working fine. My only concern now is that the client id is somehow required and I'm going to end up with some nasty bug due to it.
Hope this works for you if you try it out!
Related
I am working on a Ruby on Rails application and it is deployed on AWS Beanstalk. My Beanstalk application has two environments:
- Web Env
- config:
- Ruby 2.4.3
- Rails 5.1.4
- Puma as App server
- Nginx as Web Server
- Uses active_elastic_job
- Worker Env
- config:
- Ruby 2.4.3
- Rails 5.1.4
- Puma as App server
- Nginx as Web server
- Uses Amazon - SQS
- Uses active_elastic_job
Both Envs uses the same repo/codebase and my app was fully configured.
Last week, I came to know that my application is not force redirecting to https. Though, I was able to access my site with https but when accessed via http or accessing directly via the domain name was not redirecting me to secure site.
I came across with this link https://gist.github.com/petelacey/e35c98f9a35063a89fa9 and after deploying this file using .ebextensions on Web Env, I am now able to redirect to https --- Till here no problem
But, when I tried deploying the same Running version to my Worker Env, my background jobs have stopped working
To troubleshoot that, I ssh into my Worker env and inspected below files:
/var/log/nginx/error.log -- Nothing suspicious found
/var/log/puma/puma.log -- Nothing suspicious found
/var/log/aws-sqsd/default.log -- I see lots of http-err
/var/log/amazon/ssm/errors.log
2018-05-08 11:28:19 ERROR [HandleAwsError # awserr.go.48] [instanceID=i-YYYYYYYYYY] [MessagingDeliveryService] [Association] error when calling AWS APIs. error details - AccessDeniedException: User: arn:aws:sts::XXXXXXXXXX:assumed-role/role/i-YYYYYYYYYY is not authorized to perform: ssm:ListInstanceAssociations on resource: arn:aws:ec2:us-east-1:XXXXXXXXXX:instance/i-YYYYYYYYYY
status code: 400, request id: ''
2018-05-08 11:28:19 ERROR [HandleAwsError # awserr.go.48] [instanceID=i-YYYYYYYYYY] [MessagingDeliveryService] [Association] error when calling AWS APIs. error details - AccessDeniedException: User: arn:aws:sts::XXXXXXXXXX:assumed-role/aws-elasticbeanstalk-ec2-role/i-YYYYYYYYYY is not authorized to perform: ssm:ListAssociations on resource: arn:aws:ssm:us-east-1:XXXXXXXXXX:*
status code: 400, request id: ''
2018-05-08 11:28:19 ERROR [ProcessAssociation # processor.go.157] [instanceID=i-YYYYYYYYYY] [MessagingDeliveryService] [Association] Unable to load instance associations, unable to retrieve associations unable to retrieve associations AccessDeniedException: User: arn:aws:sts::XXXXXXXXXX:assumed-role/aws-elasticbeanstalk-ec2-role/i-YYYYYYYYYY is not authorized to perform: ssm:ListAssociations on resource: arn:aws:ssm:us-east-1:XXXXXXXXXX:*
status code: 400, request id: ''
Before rolling this nginx proxy file, everything was working fine. I am not sure what I did wrong?
Two things I am trying immediately:
Override /etc/nginx/conf.d/proxy.conf on my worker env manually with the old proxy.conf file I have.
Restart nginx to see if job/s are back to normal
But few points I would like to point here:
Both the ENVs are not supposed to use the same Running version?
If my above approach works, that means I will have 2 different proxy files on different ENV. In future, if I deploy to my worker ENV, it will override the custom one. Can this be skipped?
Thanks for the help in advance!
I got the solution for this. My friend told me to handle this in below way:
STEP:1 inside config/environments/production.rb
change config.force_ssl = true to config.force_ssl = 'web'.eql?(ENV.fetch('EB_ENV', 'web'))
STEP:2 Define EB_ENVenvironment variable as web for Web ENV or worker/whatever you like for Worker ENV
Thanks friend! Much appreciated.
I made live chat using actioncable. This works perfectly locally. However, heroku's view / page does not render.
Is redis essential for heroku to work?
I also wrote the code in product.rb
config.action_cable.allowed_request_origins = ['https://my-url-45158.herokuapp.com', 'http://my-url-45158.herokuapp.com']
config.web_socket_server_url = "wss://my-url-45158.herokuapp.com/cable"
afaik yes it is, see this,
https://blog.heroku.com/real_time_rails_implementing_websockets_in_rails_5_with_action_cable
and this
http://edgeguides.rubyonrails.org/action_cable_overview.html#configuration
when in production mode rails use redis for its subscription adapter.
as written in the documentation
by default redis for production and async for development and test environments
beside that there is PostgreSQL Adapter and Async Adapter(but should not be used for production)
I wanted to use an external Database with my heroku application. But I'm unable to edit the configuration cariables. I tried using GUI, Which says, Cannot overwrite attachment values DATABASE_URL. While I tried using CLI as well. I used the command: heroku config:addDATABASE_URL="postgresql://username:password#IP:PORT". However, this throws an error ... is not a heroku command.
After trying out most these answers, I came across an update in 2016, here:
the database needs to be detached first, then update the variable of the DATABASE_URL.
heroku addons:attach heroku-postgresql -a <app_name> --as HEROKU_DATABASE
heroku addons:detach DATABASE -a <app_name>
heroku config:add DATABASE_URL=
An alternative method which does not require detaching (which may not be a desired outcome of the switch) is to simply attach the new database and then promote it, which the Heroku Documents explicitly states as a way to set the DATABASE_URL.
heroku addons:attach heroku-postgresql -a <app_name>
heroku pg:promote heroku-postgresql -a <app_name>
I got the very same situation today when I need to change postgres to postgis. Detach doesn't work for me so I done this to database.yml:
production:
url: <%= ENV['DATABASE_URL'].sub(/^postgres/, "postgis") %>
https://github.com/rgeo/activerecord-postgis-adapter/issues/214.
SQLAlchemy 1.4.x has removed support for the postgres:// URI scheme, which is used by Heroku Postgres (https://github.com/sqlalchemy/sqlalchemy/issues/6083). To maintain compatibility, perform the following before setting up connections with SQLAlchemy:
import os
import re
uri = os.getenv("DATABASE_URL") # or other relevant config var
if uri.startswith("postgres://"):
uri = uri.replace("postgres://", "postgresql://", 1)
# rest of connection code using the connection string `uri`
This will allow you to connect to Heroku Postgres services using SQLAlchemy >= 1.4.x
As explained in this article, the correct syntax to set/add a configuration variable is
$ heroku config:set DATABASE_URL="postgresql://username:password#IP:PORT"
However, it looks like (see the comments) the DATABASE_URL has been deprecated and trying to update it will trigger an error.
Based on the Heroku docs this is how you would share a database with multiple apps.
heroku addons:attach my-originating-app::DATABASE --app sushi
Solved it. Just for the reference of the users who have the same issue or want to have a similar implementation. Here's the workaround which worked for me.
Heroku no more overwrites databse.yml, so I just modified the DATBASE_URL in the database.yml and pushed it :)
It worked too!
Source
In my case, I needed to launch an java spring boot application with my personal data base (postgres). I have an instance on AWS, and when loading the app, an error was occurring because it would connect without ssl.
Considering this documentation (https://devcenter.heroku.com/articles/connecting-to-relational-databases-on-heroku-with-java#using-ssl-with-postgresql), it says:
We used to suggest adding the URL parameter sslmode=disable to JDBC URLs. We now require use of SSL for all new Heroku Postgres databases. We will be enforcing use of SSL on all Heroku Postgres databases from March 2018. Please do not disable SSL for your database or your applications may break.
So, resuming, step 1, I deleted my addon Heroku Postgres on Resources tab.
Step 2, I changed my application.yml
from:
datasource:
driver-class-name: org.postgresql.Driver
url: jdbc:postgresql://<url>:<port>/<dataBaseName>?createDatabaseIfNotExist=true&useSSL=false
username: <user>
password: <pass>
to
datasource:
driver-class-name: org.postgresql.Driver
url: jdbc:postgresql://<url>:<port>/<dataBaseName>?createDatabaseIfNotExist=true&useSSL=false&sslmode=disable
username: <user>
password: <pass>
I added "&sslmode=disable" at the end of url string.
And finally, rebuild/deploy (which in my case is automatic after pushing into my repo on github).
I hope this would help someone.
Peace...
One way to edit the DATABASE_URL will be to create another app and add the heroku_postgres add-on there and then grab the url of that database and use that in your main app by configuring the environment variables and set the value of DATABASE_URL to that url of the database.
Now you can easily change the DATABASE_URL as that is not attached with the app.
I have an ember-cli application that I'm deploying to Divshot using the ember-cli-divshot addon. In my config/environment.js file I want to have a different api between development and production.
Inside var ENV = {} I have:
api: 'http://localhost:3000'
And the I have this for production:
if (environment === 'production')
ENV.api = '<my production api>'
}
However when I do divshot push production, my Ember app is trying to hit the localhost endpoint for the api.
After some work I realized that I need to make sure the I'm building and deploying the production version of my Ember app, which is actually built into the ember-cli-divshot addon by prepending the deploy command with ember like this:
ember divshot push production
There are lots of secrets that apps have that need to be secured in production when running in public cloud and PaaS environments. Common one is database.yml entries for mysql user and password, but there can be others. Your Google App secret, facebook app secret,... the list goes on. There are no clear way of securing these essentially configuration parameters. You DO NOT want to put these in a file as there is no guarantee who will have access to it.
In Heroku you can specify things via environment variables. In Cloudbees (a Java PaaS) you can specify these as Java System properties. Both Heroku and Cloudbees have a commandline utility for uploading this configuration parameters but there is no support for making this work both in development and production easily.
Question is how do you configure your parameters so that you can develop easily in development but not have the production secret be available in development
Ideally there would be a gem that will work in ruby and jruby environment and PaaS that will allow me to specify me secrets in a YML file that has development settings in development but actual production secrets pulled in from ENV or java.lang.System.getProperty.
##
# file: config/secure_config.yml
development:
db:
user_id: 'dev_mysql_user'
password: 'my_dev_pwd'
google:
app_id: 'xxxxx' # this is the secret for the dev app so it can be visible
app_secret: 'xxxxx'
# ...
production:
db:
user_id: <%= get_secure_config %>
password: <%= get_secure_config %>
google:
app_id: <%= get_secure_config %>
app_secret: <%= get_secure_config %>
Where the get_secure_config helper gets the value from ENV or java.lang.System.getProperty in case of Ruby or jRuby. The finally you can use them in your app as needed. For example in database.yml or in the devise code to authenticate using google.
# config/database.yml
# ...
production:
adapter: mysql2
username: <%= SecureConfig.db.user_id %>
password: <%= SecureConfig.db.password %>
And then for extra coolness the gem should also give me an executable that allows me to push the config to my PaaS
~/work/myproject> bundle exec secure_config -push_to_heroku
or
~/work/myproject> bundle exec secure_config -push_to_cloudbees
Check out Figaro. It's almost exactly what you're after.
You place your sensitive data in a git-ignored YAML file, which are then made available to the app in ENV. It also provides a rake task for configuring your Heroku instance with the variables.
As Daniel Wright suggested above Figaro is great! It does every thing I need for ruby on rails. I needed the same support on JRuby on rails and properties via JVM system properties for Cloudbees PaaS service as well. I have forked Figaro and made these extensions and sent a pull request to laserlemon/Figaro. In the mean time you can pull it using git directive in your gem file.
gem 'figaro', '0.4.2', :git => "git://github.com/RedMicaInc/figaro.git"
Main differences are documented below
How does it work?
It works really well.
There are a few similar solutions out there, and a lot of homegrown attempts. Most namespace your configuration under a Config (or similar) namespace. That's fine, but there's already a place to describe the application environment… ENV!
ENV is a collection of simple string key/value pairs and it works just great for application configuration.
These configuration parameters are also then made available as properties of FigaroSettings object. So if you had a property called MY_PROP you can use it in your code or configuration files using FigaroSettings.my_prop or FigaroSettings.MY_PROP
For JRUBY based applications properties stored in JVM system properties are also available in a similar manner. For instance if you had a property called MY_JAVA_PROP it is accessible as FigaroSettings.MY_JAVA_PROP. Java properties are case sensitive.
As an added bonus, this is exactly how apps on Heroku or Cloudbees are configured. So if you configure your Rails app using ENV, you're already set to deploy to Heroku. For Cloudbees you can use ENV or JVM properties similarly using FigaroSettings.<property>
How does it work with Cloudbees?
Cloudbees provides application configuration in a similar manner.
Typically, to configure your application parameters accessible via JVM system properties, you would do the following from the command line using the cloudbees sdk:
cloudbees config:set -a <my_app> PUSHER_APP_ID=8926
cloudbees config:set -a <my_app> PUSHER_KEY=0463644d89a340ff1132
cloudbees config:set -a <my_app> PUSHER_SECRET=0eadfd9847769f94367b
But Figaro provides a rake task to do just that! Just run:
rake figaro:cloudbees
Optionally, you can pass in the name of the Cloudbees app:
rake figaro:cloudbees[my-awesome-app]
If you just want to see the commands used you can run rake figaro:heroku_test