Add Heroku deployment support

This commit is contained in:
Effy Elden 2017-01-17 22:00:03 +11:00
parent 6cf44ca92c
commit ab4f5f5da5
8 changed files with 126 additions and 4 deletions

1
Procfile Normal file
View file

@ -0,0 +1 @@
web: bundle exec puma -C config/puma.rb

View file

@ -118,6 +118,19 @@ Which will re-create the updated containers, leaving databases and data as is. D
Docker is great for quickly trying out software, but it has its drawbacks too. If you prefer to run Mastodon without using Docker, refer to the [production guide](https://github.com/tootsuite/mastodon/wiki/Production-guide) for examples, configuration and instructions. Docker is great for quickly trying out software, but it has its drawbacks too. If you prefer to run Mastodon without using Docker, refer to the [production guide](https://github.com/tootsuite/mastodon/wiki/Production-guide) for examples, configuration and instructions.
## Deployment on Heroku (experimental)
[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy)
Mastodon can theoretically run indefinitely on a free [Heroku](https://heroku.com) app. It should be noted this has limited testing and could have unpredictable results.
1. Click the above button.
2. Fill in the options requested.
* You can use a .herokuapp.com domain, which will be simple to set up, or you can use a custom domain. If you want a custom domain and HTTPS, you will need to upgrade to a paid plan (to use Heroku's SSL features), or set up [CloudFlare](https://cloudflare.com) who offer free "Flexible SSL" (note: CloudFlare have some undefined limits on WebSockets. So far, no one has reported hitting concurrent connection limits).
* You will want Amazon S3 for file storage. The only exception is for development purposes, where you may not care if files are not saaved. Follow a guide online for creating a free Amazon S3 bucket and Access Key, then enter the details.
* If you want your Mastodon to be able to send emails, configure SMTP settings here (or later). Consider using [Mailgun](https://mailgun.com) or similar, who offer free plans that should suit your interests.
3. Deploy! The app should be set up, with a working web interface and database. You can change settings and manage versions from the Heroku dashboard.
## Development with Vagrant ## Development with Vagrant
A quick way to get a development environment up and running is with Vagrant. You will need recent versions of [Vagrant](https://www.vagrantup.com/) and [VirtualBox](https://www.virtualbox.org/) installed. A quick way to get a development environment up and running is with Vagrant. You will need recent versions of [Vagrant](https://www.vagrantup.com/) and [VirtualBox](https://www.virtualbox.org/) installed.

91
app.json Normal file
View file

@ -0,0 +1,91 @@
{
"name": "Mastodon",
"description": "A GNU Social-compatible microblogging server",
"repository": "https://github.com/tootsuite/mastodon",
"logo": "https://github.com/tootsuite/mastodon/raw/master/app/assets/images/logo.png",
"env": {
"HEROKU": {
"description": "Leave this as true",
"value": "true",
"required": true
},
"LOCAL_DOMAIN": {
"description": "The domain that your Mastodon instance will run on (this can be appname.herokuapp.com or a custom domain)",
"required": true
},
"LOCAL_HTTPS": {
"description": "Will your domain support HTTPS? (Automatic for herokuapp, requires manual configuration for custom domains)",
"value": "false",
"required": true
},
"PAPERCLIP_SECRET": {
"description": "The secret key for storing media files",
"generator": "secret"
},
"SECRET_KEY_BASE": {
"description": "The secret key base",
"generator": "secret"
},
"SINGLE_USER_MODE": {
"description": "Should the instance run in single user mode? (Disable registrations, redirect to front page)",
"value": "false",
"required": true
},
"S3_ENABLED": {
"description": "Should Mastodon use Amazon S3 for storage? This is highly recommended, as Heroku does not have persistent file storage (files will be lost).",
"value": "true",
"required": false
},
"S3_BUCKET": {
"description": "Amazon S3 Bucket",
"required": false
},
"S3_REGION": {
"description": "Amazon S3 region that the bucket is located in",
"required": false
},
"AWS_ACCESS_KEY_ID": {
"description": "Amazon S3 Access Key",
"required": false
},
"AWS_SECRET_ACCESS_KEY": {
"description": "Amazon S3 Secret Key",
"required": false
},
"SMTP_SERVER": {
"description": "Hostname for SMTP server, if you want to enable email",
"required": false
},
"SMTP_PORT": {
"description": "Port for SMTP server",
"required": false
},
"SMTP_LOGIN": {
"description": "Username for SMTP server",
"required": false
},
"SMTP_PASSWORD": {
"description": "Password for SMTP server",
"required": false
},
"SMTP_DOMAIN": {
"description": "Domain for SMTP server. Will default to instance domain if blank.",
"required": false
}
},
"buildpacks": [
{
"url": "heroku/nodejs"
},
{
"url": "heroku/ruby"
}
],
"scripts": {
"postdeploy": "bundle exec rails db:migrate && bundle exec rails db:seed"
},
"addons": [
"heroku-postgresql",
"heroku-redis"
]
}

View file

@ -7,4 +7,4 @@ test:
production: production:
adapter: redis adapter: redis
url: redis://<%= ENV['REDIS_HOST'] || 'localhost' %>:<%= ENV['REDIS_PORT'] || 6379 %>/1 url: redis://<%= ENV['REDIS_PASSWORD'] ? ':' + ENV['REDIS_PASSWORD'] + '@' : '' %><%= ENV['REDIS_HOST'] || 'localhost' %>:<%= ENV['REDIS_PORT'] || 6379 %>/1

View file

@ -45,10 +45,20 @@ Rails.application.configure do
# Use a different logger for distributed setups. # Use a different logger for distributed setups.
# config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
# Parse and split the REDIS_URL if passed (used with hosting platforms such as Heroku).
# Set ENV variables because they are used elsewhere.
if ENV['REDIS_URL']
redis_url = URI.parse(ENV['REDIS_URL'])
ENV['REDIS_HOST'] = redis_url.host
ENV['REDIS_PORT'] = redis_url.port.to_s
ENV['REDIS_PASSWORD'] = redis_url.password
end
# Use a different cache store in production. # Use a different cache store in production.
config.cache_store = :redis_store, { config.cache_store = :redis_store, {
host: ENV.fetch('REDIS_HOST') { 'localhost' }, host: ENV.fetch('REDIS_HOST') { 'localhost' },
port: ENV.fetch('REDIS_PORT') { 6379 }, port: ENV.fetch('REDIS_PORT') { 6379 },
password: ENV.fetch('REDIS_PASSWORD') { false },
db: 0, db: 0,
namespace: 'cache', namespace: 'cache',
expires_in: 20.minutes expires_in: 20.minutes
@ -85,7 +95,7 @@ Rails.application.configure do
:address => ENV['SMTP_SERVER'], :address => ENV['SMTP_SERVER'],
:user_name => ENV['SMTP_LOGIN'], :user_name => ENV['SMTP_LOGIN'],
:password => ENV['SMTP_PASSWORD'], :password => ENV['SMTP_PASSWORD'],
:domain => config.x.local_domain, :domain => ENV['SMTP_DOMAIN'] || config.x.local_domain,
:authentication => :plain, :authentication => :plain,
} }

View file

@ -3,5 +3,6 @@
Redis.current = Redis.new( Redis.current = Redis.new(
host: ENV.fetch('REDIS_HOST') { 'localhost' }, host: ENV.fetch('REDIS_HOST') { 'localhost' },
port: ENV.fetch('REDIS_PORT') { 6379 }, port: ENV.fetch('REDIS_PORT') { 6379 },
password: ENV.fetch('REDIS_PASSWORD') { false },
driver: :hiredis driver: :hiredis
) )

View file

@ -1,10 +1,11 @@
host = ENV.fetch('REDIS_HOST') { 'localhost' } host = ENV.fetch('REDIS_HOST') { 'localhost' }
port = ENV.fetch('REDIS_PORT') { 6379 } port = ENV.fetch('REDIS_PORT') { 6379 }
password = ENV.fetch('REDIS_PASSWORD') { false }
Sidekiq.configure_server do |config| Sidekiq.configure_server do |config|
config.redis = { host: host, port: port } config.redis = { host: host, port: port, password: password}
end end
Sidekiq.configure_client do |config| Sidekiq.configure_client do |config|
config.redis = { host: host, port: port } config.redis = { host: host, port: port, password: password }
end end

View file

@ -40,6 +40,11 @@ preload_app!
# cannot share connections between processes. # cannot share connections between processes.
# #
on_worker_boot do on_worker_boot do
if ENV["HEROKU"] #Spwan the workers from Puma, to only use one dyno
@sidekiq_pid ||= spawn('bundle exec sidekiq -q default -q mailers -q push')
end
ActiveRecord::Base.establish_connection if defined?(ActiveRecord) ActiveRecord::Base.establish_connection if defined?(ActiveRecord)
end end