├── .gitignore ├── README.md ├── Vagrantfile ├── deploy.rb ├── handlers └── main.yml ├── hosts.example ├── rails-app-local.yml ├── rails-app.yml ├── roles ├── database │ ├── tasks │ │ ├── main.yml │ │ ├── postgresql.yml │ │ └── redis.yml │ └── templates │ │ ├── pg_hba.conf.j2 │ │ └── postgresql.conf.j2 └── webserver │ ├── tasks │ ├── deploy.yml │ ├── main.yml │ ├── nginx.yml │ └── puma.yml │ └── templates │ ├── database.yml.j2 │ ├── etc_init_puma.j2 │ ├── etc_nginx_sites-available_app.conf.j2 │ ├── etc_puma.conf.j2 │ ├── puma-manager.j2 │ └── puma_production.j2 └── vars └── defaults.yml /.gitignore: -------------------------------------------------------------------------------- 1 | .vagrant 2 | hosts 3 | vagrant_ansible_inventory_default 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ansible Rails 2 | 3 | *Adapted from https://github.com/radar/ansible-rails-app* 4 | 5 | #### Installed Software 6 | 7 | - Ruby 2.1 8 | - PostgreSQL 9 | - nginx 10 | - Puma (jungle) 11 | 12 | #### Configuration 13 | 14 | 1. Change the app name and deploy directory in `vars/defaults.yml` 15 | 2. Rename `hosts.example` to `hosts` and change it to your hosts. For Homebrew's 16 | ansible, this defaults to `/usr/local/etc/ansible/hosts` 17 | 18 | #### Running 19 | 20 | If you're using vagrant to create the box, please use the insecure SSH key `--private-key= ~/.vagrant.d/insecure_private_key` in the `ansible-playbook` command. 21 | 22 | $ ansible-playbook -i hosts rails-app.yml -t deploy,postgresql,nginx 23 | $ 24 | $ ansible-playbook -i hosts rails-app.yml -t puma 25 | 26 | There is an example Capistrano `deploy.rb` in this repository that you can use too. 27 | 28 | # Using vagrant to spin up a local dev box 29 | #### requirements 30 | 1. install [Vagrant][vagrant] 31 | 2. install [VirtualBox][vbox] 32 | 3. install [VirtualBox guest additions plugin][vbguest] 33 | 4. install [VirtualBox hosts updater plugin][hosts] 34 | 35 | #### Running 36 | Navigate to the root ansible-rails directory and run the following command: 37 | 38 | $ vagrant up 39 | This will do: 40 | 1. download the virtualbox file (ubuntu) 41 | 2. spin it up 42 | 3. run the playbook rails-app-local.yml 43 | 4. update hosts file so your server can be accessed at 44 | 45 | [vbox]: https://www.virtualbox.org/wiki/Downloads 46 | [vagrant]: http://downloads.vagrantup.com/ 47 | [vbguest]: https://github.com/dotless-de/vagrant-vbguest 48 | [hosts]: https://github.com/cogitatio/vagrant-hostsupdater 49 | -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | Vagrant.configure("2") do |config| 2 | config.vm.box = "precise64" 3 | config.vm.box_url = "http://files.vagrantup.com/precise64.box" 4 | config.vm.host_name = "rails-prototype-host" 5 | 6 | private_ip = "192.168.13.37" 7 | config.vm.network(:private_network, :ip => private_ip) 8 | 9 | #config.vm.provision :ansible do |ansible| 10 | # ansible.extra_vars = { ansible_ssh_user: 'vagrant' } 11 | # ansible.playbook = "rails-app-local.yml" 12 | #end 13 | 14 | if defined?(VagrantPlugins::HostsUpdater) 15 | config.hostsupdater.aliases = ["local-seer.slickage.com"] 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /deploy.rb: -------------------------------------------------------------------------------- 1 | set :application, 'seer' 2 | set :repo_url, 'git://github.com/slickage/seer' 3 | set :deploy_to, '/data/seer' 4 | set :log_level, :debug 5 | set :linked_files, %w{config/database.yml} 6 | set :linked_dirs, %w{tmp/sockets log config/puma public/seer} 7 | set :sockets_path, Pathname.new("#{fetch(:deploy_to)}/shared/tmp/sockets/") 8 | 9 | # These puma settings are only here because capistrano-puma is borked. 10 | # See issue #4. 11 | set :puma_roles, :app 12 | set :puma_socket, "unix://#{fetch(:sockets_path).join('puma_' + fetch(:application) + '.sock')}" 13 | set :pumactl_socket, "unix://#{fetch(:sockets_path).join('pumactl_' + fetch(:application) + '.sock')}" 14 | set :puma_state, fetch(:sockets_path).join('puma.state') 15 | set :puma_log, -> { shared_path.join("log/puma-#{fetch(:stage )}.log") } 16 | set :puma_flags, nil 17 | 18 | set :bundle_flags, '--deployment' 19 | 20 | namespace :deploy do 21 | task :restart do 22 | invoke 'puma:restart' 23 | end 24 | end 25 | 26 | namespace :seed_sample do 27 | task :load do 28 | on roles(:app) do 29 | within release_path do 30 | ask(:confirm, "Are you sure you want to delete everything and start again? Type 'yes'") 31 | if fetch(:confirm) == "yes" 32 | execute :rake, "db:reset AUTO_ACCEPT=true" 33 | execute :rake, "seed_sample:load" 34 | end 35 | end 36 | end 37 | end 38 | end 39 | 40 | namespace :puma do 41 | desc "Restart puma instance for this application" 42 | task :restart do 43 | on roles fetch(:puma_roles) do 44 | within release_path do 45 | execute :bundle, "exec pumactl -S #{fetch(:puma_state)} restart" 46 | end 47 | end 48 | end 49 | 50 | desc "Show status of puma for this application" 51 | task :status do 52 | on roles fetch(:puma_roles) do 53 | within release_path do 54 | execute :bundle, "exec pumactl -S #{fetch(:puma_state)} stats" 55 | end 56 | end 57 | end 58 | 59 | desc "Show status of puma for all applications" 60 | task :overview do 61 | on roles fetch(:puma_roles) do 62 | within release_path do 63 | execute :bundle, "exec puma status" 64 | end 65 | end 66 | end 67 | end 68 | -------------------------------------------------------------------------------- /handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "Restart Redis" 3 | sudo: yes 4 | service: name=redis-server state=restarted 5 | -------------------------------------------------------------------------------- /hosts.example: -------------------------------------------------------------------------------- 1 | 192.168.165.135 ansible_ssh_user=vagrant ansible_ssh_private_key_file=~/.vagrant.d/insecure_private_key 2 | -------------------------------------------------------------------------------- /rails-app-local.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | user: vagrant 4 | sudo: yes 5 | vars_files: 6 | - vars/defaults.yml 7 | 8 | roles: 9 | - webserver 10 | - database 11 | 12 | handlers: 13 | - name: Restart puma 14 | action: service name=puma state=restarted 15 | -------------------------------------------------------------------------------- /rails-app.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | user: vagrant 4 | sudo: True 5 | vars_files: 6 | - vars/defaults.yml 7 | 8 | roles: 9 | - webserver 10 | - database 11 | 12 | handlers: 13 | - name: Restart puma 14 | action: service name=puma state=restarted 15 | -------------------------------------------------------------------------------- /roles/database/tasks/main.yml: -------------------------------------------------------------------------------- 1 | - include: postgresql.yml tags=postgresql 2 | - include: redis.yml tags=redis 3 | -------------------------------------------------------------------------------- /roles/database/tasks/postgresql.yml: -------------------------------------------------------------------------------- 1 | - name: Install PostgreSQL dependencies 2 | action: apt pkg={{item}} state=latest 3 | with_items: 4 | - python-pycurl 5 | - python-psycopg2 6 | 7 | - name: Add PostgreSQL repo key 8 | apt_key: url=http://apt.postgresql.org/pub/repos/apt/ACCC4CF8.asc 9 | 10 | - name: Add PostgreSQL repo 11 | apt_repository: repo='deb http://apt.postgresql.org/pub/repos/apt/ precise-pgdg main' 12 | 13 | - name: Install PostgreSQL 14 | apt: pkg=postgresql-9.3 state=latest update_cache=true 15 | 16 | - name: Copy valid pg_hba.conf 17 | template: src=pg_hba.conf.j2 dest=/etc/postgresql/9.3/main/pg_hba.conf 18 | 19 | - name: Copy valid postgresql.conf 20 | template: src=postgresql.conf.j2 dest=/etc/postgresql/9.3/main/postgresql.conf 21 | 22 | - name: Restart PostgreSQL 23 | command: service postgresql restart 24 | 25 | - name: create the postgresql user for application 26 | postgresql_user: name=deploy 27 | sudo: yes 28 | sudo_user: postgres 29 | 30 | - name: create the postgresql database for application 31 | postgresql_db: name=app_{{app_name}} owner=deploy state=present 32 | sudo: yes 33 | sudo_user: postgres 34 | -------------------------------------------------------------------------------- /roles/database/tasks/redis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Install Redis server 3 | - name: "Install Redis server" 4 | sudo: yes 5 | action: apt pkg=redis-server state=latest update-cache=yes 6 | 7 | # Bind Redis server to all interfaces 8 | - name: "Bind Redis server to all interfaces" 9 | sudo: yes 10 | action: lineinfile dest=/etc/redis/redis.conf state=present regexp="^#?bind" line="#bind 127.0.0.1" 11 | notify: 12 | - "Restart Redis" 13 | 14 | # Ensure Redis server is running 15 | - name: "Ensure Redis server is running" 16 | sudo: yes 17 | action: service name=redis-server state=started -------------------------------------------------------------------------------- /roles/database/templates/pg_hba.conf.j2: -------------------------------------------------------------------------------- 1 | local all all peer 2 | host all all 127.0.0.1/32 md5 3 | host all all ::1/128 md5 4 | host all all 10.11.12.0/24 md5 5 | 6 | -------------------------------------------------------------------------------- /roles/database/templates/postgresql.conf.j2: -------------------------------------------------------------------------------- 1 | # ----------------------------- 2 | # PostgreSQL configuration file 3 | # ----------------------------- 4 | # 5 | # This file consists of lines of the form: 6 | # 7 | # name = value 8 | # 9 | # (The "=" is optional.) Whitespace may be used. Comments are introduced with 10 | # "#" anywhere on a line. The complete list of parameter names and allowed 11 | # values can be found in the PostgreSQL documentation. 12 | # 13 | # The commented-out settings shown in this file represent the default values. 14 | # Re-commenting a setting is NOT sufficient to revert it to the default value; 15 | # you need to reload the server. 16 | # 17 | # This file is read on server startup and when the server receives a SIGHUP 18 | # signal. If you edit the file on a running system, you have to SIGHUP the 19 | # server for the changes to take effect, or use "pg_ctl reload". Some 20 | # parameters, which are marked below, require a server shutdown and restart to 21 | # take effect. 22 | # 23 | # Any parameter can also be given as a command-line option to the server, e.g., 24 | # "postgres -c log_connections=on". Some parameters can be changed at run time 25 | # with the "SET" SQL command. 26 | # 27 | # Memory units: kB = kilobytes Time units: ms = milliseconds 28 | # MB = megabytes s = seconds 29 | # GB = gigabytes min = minutes 30 | # h = hours 31 | # d = days 32 | 33 | 34 | #------------------------------------------------------------------------------ 35 | # FILE LOCATIONS 36 | #------------------------------------------------------------------------------ 37 | 38 | # The default values of these variables are driven from the -D command-line 39 | # option or PGDATA environment variable, represented here as ConfigDir. 40 | 41 | data_directory = '/var/lib/postgresql/9.3/main' # use data in another directory 42 | # (change requires restart) 43 | hba_file = '/etc/postgresql/9.3/main/pg_hba.conf' # host-based authentication file 44 | # (change requires restart) 45 | ident_file = '/etc/postgresql/9.3/main/pg_ident.conf' # ident configuration file 46 | # (change requires restart) 47 | 48 | # If external_pid_file is not explicitly set, no extra PID file is written. 49 | external_pid_file = '/var/run/postgresql/9.3-main.pid' # write an extra PID file 50 | # (change requires restart) 51 | 52 | 53 | #------------------------------------------------------------------------------ 54 | # CONNECTIONS AND AUTHENTICATION 55 | #------------------------------------------------------------------------------ 56 | 57 | # - Connection Settings - 58 | 59 | listen_addresses = 'localhost, 10.11.12.13' # what IP address(es) to listen on; 60 | # comma-separated list of addresses; 61 | # defaults to 'localhost', '*' = all 62 | # (change requires restart) 63 | port = 5432 # (change requires restart) 64 | max_connections = 100 # (change requires restart) 65 | # Note: Increasing max_connections costs ~400 bytes of shared memory per 66 | # connection slot, plus lock space (see max_locks_per_transaction). 67 | #superuser_reserved_connections = 3 # (change requires restart) 68 | unix_socket_directories = '/var/run/postgresql' # (change requires restart) 69 | #unix_socket_group = '' # (change requires restart) 70 | #unix_socket_permissions = 0777 # begin with 0 to use octal notation 71 | # (change requires restart) 72 | #bonjour = off # advertise server via Bonjour 73 | # (change requires restart) 74 | #bonjour_name = '' # defaults to the computer name 75 | # (change requires restart) 76 | 77 | # - Security and Authentication - 78 | 79 | #authentication_timeout = 1min # 1s-600s 80 | ssl = false # (change requires restart) 81 | #ssl_ciphers = 'ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH' # allowed SSL ciphers 82 | # (change requires restart) 83 | #ssl_renegotiation_limit = 512MB # amount of data between renegotiations 84 | #password_encryption = on 85 | #db_user_namespace = off 86 | 87 | # Kerberos and GSSAPI 88 | #krb_server_keyfile = '' 89 | #krb_srvname = 'postgres' # (Kerberos only) 90 | #krb_caseins_users = off 91 | 92 | # - TCP Keepalives - 93 | # see "man 7 tcp" for details 94 | 95 | #tcp_keepalives_idle = 0 # TCP_KEEPIDLE, in seconds; 96 | # 0 selects the system default 97 | #tcp_keepalives_interval = 0 # TCP_KEEPINTVL, in seconds; 98 | # 0 selects the system default 99 | #tcp_keepalives_count = 0 # TCP_KEEPCNT; 100 | # 0 selects the system default 101 | 102 | 103 | #------------------------------------------------------------------------------ 104 | # RESOURCE USAGE (except WAL) 105 | #------------------------------------------------------------------------------ 106 | 107 | # - Memory - 108 | 109 | shared_buffers = 24MB # min 128kB 110 | # (change requires restart) 111 | temp_buffers = 8MB # min 800kB 112 | #max_prepared_transactions = 0 # zero disables the feature 113 | # (change requires restart) 114 | # Note: Increasing max_prepared_transactions costs ~600 bytes of shared memory 115 | # per transaction slot, plus lock space (see max_locks_per_transaction). 116 | # It is not advisable to set max_prepared_transactions nonzero unless you 117 | # actively intend to use prepared transactions. 118 | #work_mem = 1MB # min 64kB 119 | #maintenance_work_mem = 16MB # min 1MB 120 | #max_stack_depth = 2MB # min 100kB 121 | 122 | # - Kernel Resource Usage - 123 | 124 | #max_files_per_process = 1000 # min 25 125 | # (change requires restart) 126 | #shared_preload_libraries = '' # (change requires restart) 127 | 128 | # - Cost-Based Vacuum Delay - 129 | 130 | #vacuum_cost_delay = 0ms # 0-100 milliseconds 131 | #vacuum_cost_page_hit = 1 # 0-10000 credits 132 | #vacuum_cost_page_miss = 10 # 0-10000 credits 133 | #vacuum_cost_page_dirty = 20 # 0-10000 credits 134 | #vacuum_cost_limit = 200 # 1-10000 credits 135 | 136 | # - Background Writer - 137 | 138 | #bgwriter_delay = 200ms # 10-10000ms between rounds 139 | #bgwriter_lru_maxpages = 100 # 0-1000 max buffers written/round 140 | #bgwriter_lru_multiplier = 2.0 # 0-10.0 multipler on buffers scanned/round 141 | 142 | # - Asynchronous Behavior - 143 | 144 | #effective_io_concurrency = 1 # 1-1000. 0 disables prefetching 145 | 146 | 147 | #------------------------------------------------------------------------------ 148 | # WRITE AHEAD LOG 149 | #------------------------------------------------------------------------------ 150 | 151 | # - Settings - 152 | 153 | #wal_level = minimal # minimal, archive, or hot_standby 154 | # (change requires restart) 155 | #fsync = on # turns forced synchronization on or off 156 | #synchronous_commit = on # synchronization level; on, off, or local 157 | #wal_sync_method = fsync # the default is the first option 158 | # supported by the operating system: 159 | # open_datasync 160 | # fdatasync (default on Linux) 161 | # fsync 162 | # fsync_writethrough 163 | # open_sync 164 | #full_page_writes = on # recover from partial page writes 165 | #wal_buffers = -1 # min 32kB, -1 sets based on shared_buffers 166 | # (change requires restart) 167 | #wal_writer_delay = 200ms # 1-10000 milliseconds 168 | 169 | #commit_delay = 0 # range 0-100000, in microseconds 170 | #commit_siblings = 5 # range 1-1000 171 | 172 | # - Checkpoints - 173 | 174 | #checkpoint_segments = 3 # in logfile segments, min 1, 16MB each 175 | #checkpoint_timeout = 5min # range 30s-1h 176 | #checkpoint_completion_target = 0.5 # checkpoint target duration, 0.0 - 1.0 177 | #checkpoint_warning = 30s # 0 disables 178 | 179 | # - Archiving - 180 | 181 | #archive_mode = off # allows archiving to be done 182 | # (change requires restart) 183 | #archive_command = '' # command to use to archive a logfile segment 184 | #archive_timeout = 0 # force a logfile segment switch after this 185 | # number of seconds; 0 disables 186 | 187 | 188 | #------------------------------------------------------------------------------ 189 | # REPLICATION 190 | #------------------------------------------------------------------------------ 191 | 192 | # - Master Server - 193 | 194 | # These settings are ignored on a standby server 195 | 196 | #max_wal_senders = 0 # max number of walsender processes 197 | # (change requires restart) 198 | #wal_sender_delay = 1s # walsender cycle time, 1-10000 milliseconds 199 | #wal_keep_segments = 0 # in logfile segments, 16MB each; 0 disables 200 | #vacuum_defer_cleanup_age = 0 # number of xacts by which cleanup is delayed 201 | #replication_timeout = 60s # in milliseconds; 0 disables 202 | #synchronous_standby_names = '' # standby servers that provide sync rep 203 | # comma-separated list of application_name 204 | # from standby(s); '*' = all 205 | 206 | # - Standby Servers - 207 | 208 | # These settings are ignored on a master server 209 | 210 | #hot_standby = off # "on" allows queries during recovery 211 | # (change requires restart) 212 | #max_standby_archive_delay = 30s # max delay before canceling queries 213 | # when reading WAL from archive; 214 | # -1 allows indefinite delay 215 | #max_standby_streaming_delay = 30s # max delay before canceling queries 216 | # when reading streaming WAL; 217 | # -1 allows indefinite delay 218 | #wal_receiver_status_interval = 10s # send replies at least this often 219 | # 0 disables 220 | #hot_standby_feedback = off # send info from standby to prevent 221 | # query conflicts 222 | 223 | 224 | #------------------------------------------------------------------------------ 225 | # QUERY TUNING 226 | #------------------------------------------------------------------------------ 227 | 228 | # - Planner Method Configuration - 229 | 230 | #enable_bitmapscan = on 231 | #enable_hashagg = on 232 | #enable_hashjoin = on 233 | #enable_indexscan = on 234 | #enable_material = on 235 | #enable_mergejoin = on 236 | #enable_nestloop = on 237 | #enable_seqscan = on 238 | #enable_sort = on 239 | #enable_tidscan = on 240 | 241 | # - Planner Cost Constants - 242 | 243 | #seq_page_cost = 1.0 # measured on an arbitrary scale 244 | #random_page_cost = 4.0 # same scale as above 245 | #cpu_tuple_cost = 0.01 # same scale as above 246 | #cpu_index_tuple_cost = 0.005 # same scale as above 247 | #cpu_operator_cost = 0.0025 # same scale as above 248 | #effective_cache_size = 128MB 249 | 250 | # - Genetic Query Optimizer - 251 | 252 | #geqo = on 253 | #geqo_threshold = 12 254 | #geqo_effort = 5 # range 1-10 255 | #geqo_pool_size = 0 # selects default based on effort 256 | #geqo_generations = 0 # selects default based on effort 257 | #geqo_selection_bias = 2.0 # range 1.5-2.0 258 | #geqo_seed = 0.0 # range 0.0-1.0 259 | 260 | # - Other Planner Options - 261 | 262 | #default_statistics_target = 100 # range 1-10000 263 | #constraint_exclusion = partition # on, off, or partition 264 | #cursor_tuple_fraction = 0.1 # range 0.0-1.0 265 | #from_collapse_limit = 8 266 | #join_collapse_limit = 8 # 1 disables collapsing of explicit 267 | # JOIN clauses 268 | 269 | 270 | #------------------------------------------------------------------------------ 271 | # ERROR REPORTING AND LOGGING 272 | #------------------------------------------------------------------------------ 273 | 274 | # - Where to Log - 275 | 276 | #log_destination = 'stderr' # Valid values are combinations of 277 | # stderr, csvlog, syslog, and eventlog, 278 | # depending on platform. csvlog 279 | # requires logging_collector to be on. 280 | 281 | # This is used when logging to stderr: 282 | #logging_collector = off # Enable capturing of stderr and csvlog 283 | # into log files. Required to be on for 284 | # csvlogs. 285 | # (change requires restart) 286 | 287 | # These are only used if logging_collector is on: 288 | #log_directory = 'pg_log' # directory where log files are written, 289 | # can be absolute or relative to PGDATA 290 | #log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log' # log file name pattern, 291 | # can include strftime() escapes 292 | #log_file_mode = 0600 # creation mode for log files, 293 | # begin with 0 to use octal notation 294 | #log_truncate_on_rotation = off # If on, an existing log file with the 295 | # same name as the new log file will be 296 | # truncated rather than appended to. 297 | # But such truncation only occurs on 298 | # time-driven rotation, not on restarts 299 | # or size-driven rotation. Default is 300 | # off, meaning append to existing files 301 | # in all cases. 302 | #log_rotation_age = 1d # Automatic rotation of logfiles will 303 | # happen after that time. 0 disables. 304 | #log_rotation_size = 10MB # Automatic rotation of logfiles will 305 | # happen after that much log output. 306 | # 0 disables. 307 | 308 | # These are relevant when logging to syslog: 309 | #syslog_facility = 'LOCAL0' 310 | #syslog_ident = 'postgres' 311 | 312 | #silent_mode = off # Run server silently. 313 | # DO NOT USE without syslog or 314 | # logging_collector 315 | # (change requires restart) 316 | 317 | 318 | # - When to Log - 319 | 320 | #client_min_messages = notice # values in order of decreasing detail: 321 | # debug5 322 | # debug4 323 | # debug3 324 | # debug2 325 | # debug1 326 | # log 327 | # notice 328 | # warning 329 | # error 330 | 331 | #log_min_messages = warning # values in order of decreasing detail: 332 | # debug5 333 | # debug4 334 | # debug3 335 | # debug2 336 | # debug1 337 | # info 338 | # notice 339 | # warning 340 | # error 341 | # log 342 | # fatal 343 | # panic 344 | 345 | #log_min_error_statement = error # values in order of decreasing detail: 346 | # debug5 347 | # debug4 348 | # debug3 349 | # debug2 350 | # debug1 351 | # info 352 | # notice 353 | # warning 354 | # error 355 | # log 356 | # fatal 357 | # panic (effectively off) 358 | 359 | #log_min_duration_statement = -1 # -1 is disabled, 0 logs all statements 360 | # and their durations, > 0 logs only 361 | # statements running at least this number 362 | # of milliseconds 363 | 364 | 365 | # - What to Log - 366 | 367 | #debug_print_parse = off 368 | #debug_print_rewritten = off 369 | #debug_print_plan = off 370 | #debug_pretty_print = on 371 | #log_checkpoints = off 372 | #log_connections = off 373 | #log_disconnections = off 374 | #log_duration = off 375 | #log_error_verbosity = default # terse, default, or verbose messages 376 | #log_hostname = off 377 | log_line_prefix = '%t ' # special values: 378 | # %a = application name 379 | # %u = user name 380 | # %d = database name 381 | # %r = remote host and port 382 | # %h = remote host 383 | # %p = process ID 384 | # %t = timestamp without milliseconds 385 | # %m = timestamp with milliseconds 386 | # %i = command tag 387 | # %e = SQL state 388 | # %c = session ID 389 | # %l = session line number 390 | # %s = session start timestamp 391 | # %v = virtual transaction ID 392 | # %x = transaction ID (0 if none) 393 | # %q = stop here in non-session 394 | # processes 395 | # %% = '%' 396 | # e.g. '<%u%%%d> ' 397 | #log_lock_waits = off # log lock waits >= deadlock_timeout 398 | #log_statement = 'none' # none, ddl, mod, all 399 | #log_temp_files = -1 # log temporary files equal or larger 400 | # than the specified size in kilobytes; 401 | # -1 disables, 0 logs all temp files 402 | #log_timezone = '(defaults to server environment setting)' 403 | 404 | 405 | #------------------------------------------------------------------------------ 406 | # RUNTIME STATISTICS 407 | #------------------------------------------------------------------------------ 408 | 409 | # - Query/Index Statistics Collector - 410 | 411 | #track_activities = on 412 | #track_counts = on 413 | #track_functions = none # none, pl, all 414 | #track_activity_query_size = 1024 # (change requires restart) 415 | #update_process_title = on 416 | #stats_temp_directory = 'pg_stat_tmp' 417 | 418 | 419 | # - Statistics Monitoring - 420 | 421 | #log_parser_stats = off 422 | #log_planner_stats = off 423 | #log_executor_stats = off 424 | #log_statement_stats = off 425 | 426 | 427 | #------------------------------------------------------------------------------ 428 | # AUTOVACUUM PARAMETERS 429 | #------------------------------------------------------------------------------ 430 | 431 | #autovacuum = on # Enable autovacuum subprocess? 'on' 432 | # requires track_counts to also be on. 433 | #log_autovacuum_min_duration = -1 # -1 disables, 0 logs all actions and 434 | # their durations, > 0 logs only 435 | # actions running at least this number 436 | # of milliseconds. 437 | #autovacuum_max_workers = 3 # max number of autovacuum subprocesses 438 | # (change requires restart) 439 | #autovacuum_naptime = 1min # time between autovacuum runs 440 | #autovacuum_vacuum_threshold = 50 # min number of row updates before 441 | # vacuum 442 | #autovacuum_analyze_threshold = 50 # min number of row updates before 443 | # analyze 444 | #autovacuum_vacuum_scale_factor = 0.2 # fraction of table size before vacuum 445 | #autovacuum_analyze_scale_factor = 0.1 # fraction of table size before analyze 446 | #autovacuum_freeze_max_age = 200000000 # maximum XID age before forced vacuum 447 | # (change requires restart) 448 | #autovacuum_vacuum_cost_delay = 20ms # default vacuum cost delay for 449 | # autovacuum, in milliseconds; 450 | # -1 means use vacuum_cost_delay 451 | #autovacuum_vacuum_cost_limit = -1 # default vacuum cost limit for 452 | # autovacuum, -1 means use 453 | # vacuum_cost_limit 454 | 455 | 456 | #------------------------------------------------------------------------------ 457 | # CLIENT CONNECTION DEFAULTS 458 | #------------------------------------------------------------------------------ 459 | 460 | # - Statement Behavior - 461 | 462 | #search_path = '"$user",public' # schema names 463 | #default_tablespace = '' # a tablespace name, '' uses the default 464 | #temp_tablespaces = '' # a list of tablespace names, '' uses 465 | # only default tablespace 466 | #check_function_bodies = on 467 | #default_transaction_isolation = 'read committed' 468 | #default_transaction_read_only = off 469 | #default_transaction_deferrable = off 470 | #session_replication_role = 'origin' 471 | #statement_timeout = 0 # in milliseconds, 0 is disabled 472 | #vacuum_freeze_min_age = 50000000 473 | #vacuum_freeze_table_age = 150000000 474 | #bytea_output = 'hex' # hex, escape 475 | #xmlbinary = 'base64' 476 | #xmloption = 'content' 477 | 478 | # - Locale and Formatting - 479 | 480 | datestyle = 'iso, mdy' 481 | #intervalstyle = 'postgres' 482 | #timezone = '(defaults to server environment setting)' 483 | #timezone_abbreviations = 'Default' # Select the set of available time zone 484 | # abbreviations. Currently, there are 485 | # Default 486 | # Australia 487 | # India 488 | # You can create your own file in 489 | # share/timezonesets/. 490 | #extra_float_digits = 0 # min -15, max 3 491 | #client_encoding = sql_ascii # actually, defaults to database 492 | # encoding 493 | 494 | # These settings are initialized by initdb, but they can be changed. 495 | lc_messages = 'en_US.UTF-8' # locale for system error message 496 | # strings 497 | lc_monetary = 'en_US.UTF-8' # locale for monetary formatting 498 | lc_numeric = 'en_US.UTF-8' # locale for number formatting 499 | lc_time = 'en_US.UTF-8' # locale for time formatting 500 | 501 | # default configuration for text search 502 | default_text_search_config = 'pg_catalog.english' 503 | 504 | # - Other Defaults - 505 | 506 | #dynamic_library_path = '$libdir' 507 | #local_preload_libraries = '' 508 | 509 | 510 | #------------------------------------------------------------------------------ 511 | # LOCK MANAGEMENT 512 | #------------------------------------------------------------------------------ 513 | 514 | #deadlock_timeout = 1s 515 | #max_locks_per_transaction = 64 # min 10 516 | # (change requires restart) 517 | # Note: Each lock table slot uses ~270 bytes of shared memory, and there are 518 | # max_locks_per_transaction * (max_connections + max_prepared_transactions) 519 | # lock table slots. 520 | #max_pred_locks_per_transaction = 64 # min 10 521 | # (change requires restart) 522 | 523 | #------------------------------------------------------------------------------ 524 | # VERSION/PLATFORM COMPATIBILITY 525 | #------------------------------------------------------------------------------ 526 | 527 | # - Previous PostgreSQL Versions - 528 | 529 | #array_nulls = on 530 | #backslash_quote = safe_encoding # on, off, or safe_encoding 531 | #default_with_oids = off 532 | #escape_string_warning = on 533 | #lo_compat_privileges = off 534 | #quote_all_identifiers = off 535 | #sql_inheritance = on 536 | #standard_conforming_strings = on 537 | #synchronize_seqscans = on 538 | 539 | # - Other Platforms and Clients - 540 | 541 | #transform_null_equals = off 542 | 543 | 544 | #------------------------------------------------------------------------------ 545 | # ERROR HANDLING 546 | #------------------------------------------------------------------------------ 547 | 548 | #exit_on_error = off # terminate session on any error? 549 | #restart_after_crash = on # reinitialize after backend crash? 550 | 551 | 552 | #------------------------------------------------------------------------------ 553 | # CUSTOMIZED OPTIONS 554 | #------------------------------------------------------------------------------ 555 | 556 | #custom_variable_classes = '' # list of custom variable class names 557 | -------------------------------------------------------------------------------- /roles/webserver/tasks/deploy.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ruby from source playbook (https://github.com/jgrowl/ansible-playbook-ruby-from-src) 3 | - name: upgrade 4 | action: apt update_cache=yes upgrade=yes 5 | 6 | - name: install ruby dependencies 7 | action: apt pkg={{item}} state=installed 8 | with_items: 9 | - build-essential 10 | - automake 11 | - bison 12 | - autoconf 13 | - pkg-config 14 | - libreadline6 15 | - libreadline6-dev 16 | - openssl 17 | - libssl-dev 18 | - curl 19 | - git-core 20 | - zlib1g 21 | - zlib1g-dev 22 | - libyaml-dev 23 | - libsqlite3-dev 24 | - libxml2-dev 25 | - libxslt1-dev 26 | - curl 27 | 28 | - name: Install app dependencies 29 | action: apt pkg={{item}} state=installed 30 | with_items: 31 | - libpq-dev 32 | - nodejs 33 | - imagemagick 34 | tags: package 35 | 36 | # Install correct version of ruby from source 37 | - name: ruby-from-src | ensure directory temporary ruby download directory is present 38 | file: state=directory path={{rubyTmpDir}} 39 | 40 | - name: ruby-from-src | Download ruby source 41 | get_url: url={{rubyUrl}} dest={{rubyTmpDir}} 42 | 43 | - name: ruby-from-src | ensure ruby is extracted 44 | command: tar -xf {{rubyCompressedFile}} chdir={{rubyTmpDir}} creates={{tmpRubyPath}} 45 | 46 | - name: ruby-from-src | ensure ruby is configured 47 | command: ./configure chdir={{tmpRubyPath}} creates={{tmpRubyPath}}/Makefile 48 | 49 | - name: ruby-from-src | ensure ruby is compiled 50 | command: make chdir={{tmpRubyPath}} creates={{tmpRubyPath}}/ruby 51 | 52 | - name: ruby-from-src | ensure ruby is installed 53 | command: make install chdir={{tmpRubyPath}} creates=/usr/local/bin/ruby 54 | 55 | - name: Create deployment user 56 | user: name=deploy comment="Application deployment user" 57 | 58 | - authorized_key: user=deploy key="{{ lookup('file', '/home/charlie/.ssh/id_rsa.pub') }}" 59 | 60 | - name: Create deployment directory 61 | file: path={{deploy_directory}} owner=deploy group=deploy state=directory 62 | 63 | - name: Make shared directories 64 | file: path={{deploy_directory}}/shared/{{item}} group=deploy owner=deploy state=directory 65 | with_items: 66 | - tmp 67 | - tmp/pids 68 | - tmp/puma 69 | - log 70 | - public 71 | - bundle 72 | - bin 73 | - config 74 | - config/puma 75 | tags: shared 76 | 77 | - name: Install database.yml 78 | template: src=database.yml.j2 dest={{deploy_directory}}/shared/config/database.yml force=yes mode=755 owner=deploy 79 | 80 | - name: Install Bundler 81 | command: gem install bundler 82 | -------------------------------------------------------------------------------- /roles/webserver/tasks/main.yml: -------------------------------------------------------------------------------- 1 | - include: deploy.yml tags=deploy 2 | - include: puma.yml tags=puma 3 | - include: nginx.yml tags=nginx -------------------------------------------------------------------------------- /roles/webserver/tasks/nginx.yml: -------------------------------------------------------------------------------- 1 | - name: Install nginx 2 | apt: pkg=nginx state=latest 3 | 4 | - name: Remove the default app 5 | command: rm -rf /etc/nginx/sites-enabled/default 6 | 7 | - name: Remove the app's config, if exists 8 | command: rm -rf /etc/nginx/sites-enabled/default 9 | 10 | - name: Remove the app's symlink, if exists 11 | command: rm -rf /etc/nginx/sites-enabled/{{app_name}} 12 | 13 | - name: Configure nginx for the app 14 | template: src=etc_nginx_sites-available_app.conf.j2 dest=/etc/nginx/sites-available/{{app_name}} group=www-data owner=www-data force=yes 15 | 16 | - name: Enable the app 17 | command: ln -s /etc/nginx/sites-available/{{app_name}} /etc/nginx/sites-enabled/{{app_name}} 18 | 19 | - name: Restart nginx 20 | action: service name=nginx state=restarted 21 | -------------------------------------------------------------------------------- /roles/webserver/tasks/puma.yml: -------------------------------------------------------------------------------- 1 | - name: Add puma-manager 2 | template: src=puma-manager.j2 dest=/etc/init/puma-manager.conf force=yes mode=755 3 | tags: puma 4 | 5 | - name: Add puma config 6 | template: src=etc_puma.conf.j2 dest=/etc/puma.conf force=yes mode=755 7 | tags: puma 8 | 9 | - name: Add puma init script 10 | template: src=etc_init_puma.j2 dest=/etc/init/puma.conf force=yes mode=755 11 | tags: puma 12 | 13 | - name: Add puma shared/config 14 | template: src=puma_production.j2 dest={{deploy_directory}}/shared/config/puma/production.rb force=yes mode=755 15 | tags: puma 16 | 17 | - name: Make shared/tmp/sockets 18 | file: path={{deploy_directory}}/shared/tmp/sockets group=deploy owner=deploy state=directory 19 | tags: tmp 20 | 21 | - name: Restart puma-manager 22 | action: service name=puma-manager state=restarted 23 | -------------------------------------------------------------------------------- /roles/webserver/templates/database.yml.j2: -------------------------------------------------------------------------------- 1 | production: 2 | adapter: postgresql 3 | database: app_{{app_name}} -------------------------------------------------------------------------------- /roles/webserver/templates/etc_init_puma.j2: -------------------------------------------------------------------------------- 1 | # /etc/init/puma.conf - Puma config 2 | 3 | # This example config should work with Ubuntu 12.04+. It 4 | # allows you to manage multiple Puma instances with 5 | # Upstart, Ubuntu's native service management tool. 6 | # 7 | # See workers.conf for how to manage all Puma instances at once. 8 | # 9 | # Save this config as /etc/init/puma.conf then manage puma with: 10 | # sudo start puma 11 | # sudo stop puma 12 | # sudo status puma 13 | # 14 | # or use the service command: 15 | # sudo service puma {start,stop,restart,status} 16 | # 17 | 18 | description "Puma Background Worker" 19 | 20 | # no "start on", we don't want to automatically start 21 | stop on (stopping puma-manager or runlevel [06]) 22 | 23 | # change apps to match your deployment user if you want to use this as a less privileged user (recommended!) 24 | setuid deploy 25 | setgid deploy 26 | 27 | respawn 28 | respawn limit 3 30 29 | 30 | instance {{deploy_directory}}/current 31 | 32 | script 33 | cd {{deploy_directory}}/current 34 | logger -t puma "Starting server: $app" 35 | exec bundle exec puma -C {{deploy_directory}}/current/config/puma/production.rb 36 | end script -------------------------------------------------------------------------------- /roles/webserver/templates/etc_nginx_sites-available_app.conf.j2: -------------------------------------------------------------------------------- 1 | upstream {{ app_name }} { 2 | server unix://{{deploy_directory}}/shared/tmp/sockets/puma_{{ app_name }}.sock; 3 | } 4 | 5 | server { 6 | gzip on; 7 | listen 80; 8 | 9 | gzip_types text/plain text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript application/json; 10 | server_name {{ webserver_name }}; 11 | root {{ deploy_directory }}/current/public; 12 | 13 | location / { 14 | proxy_pass http://{{ app_name }}; # match the name of upstream directive which is defined above 15 | proxy_set_header Host $host; 16 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 17 | } 18 | 19 | location /robots.txt {} 20 | 21 | location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ { 22 | expires 1y; 23 | log_not_found off; 24 | } 25 | 26 | location ~ ^/(assets|images|javascripts|stylesheets|swfs|system)/ { 27 | gzip_static on; 28 | expires max; 29 | add_header Cache-Control public; 30 | add_header Last-Modified ""; 31 | add_header ETag ""; 32 | 33 | break; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /roles/webserver/templates/etc_puma.conf.j2: -------------------------------------------------------------------------------- 1 | {{deploy_directory}}/current,deploy,{{deploy_directory}}/current/config/puma/production.rb,{{deploy_directory}}/current/log/puma.log 2 | -------------------------------------------------------------------------------- /roles/webserver/templates/puma-manager.j2: -------------------------------------------------------------------------------- 1 | # /etc/init/puma-manager.conf - manage a set of Pumas 2 | 3 | # This example config should work with Ubuntu 12.04+. It 4 | # allows you to manage multiple Puma instances with 5 | # Upstart, Ubuntu's native service management tool. 6 | # 7 | # See puma.conf for how to manage a single Puma instance. 8 | # 9 | # Use "stop puma-manager" to stop all Puma instances. 10 | # Use "start puma-manager" to start all instances. 11 | # Use "restart puma-manager" to restart all instances. 12 | # Crazy, right? 13 | # 14 | 15 | description "Manages the set of puma processes" 16 | 17 | # This starts upon bootup and stops on shutdown 18 | start on runlevel [2345] 19 | stop on runlevel [06] 20 | 21 | # Set this to the number of Puma processes you want 22 | # to run on this machine 23 | env PUMA_CONF="/etc/puma.conf" 24 | 25 | pre-start script 26 | for i in `cat $PUMA_CONF`; do 27 | app=`echo $i | cut -d , -f 1` 28 | logger -t "puma-manager" "Starting $app" 29 | start puma app=$app 30 | done 31 | end script -------------------------------------------------------------------------------- /roles/webserver/templates/puma_production.j2: -------------------------------------------------------------------------------- 1 | # config/puma.rb 2 | threads 1, 6 3 | workers 2 4 | 5 | on_worker_boot do 6 | require "active_record" 7 | cwd = File.dirname(__FILE__)+"/../.." 8 | ActiveRecord::Base.connection.disconnect! rescue ActiveRecord::ConnectionNotEstablished 9 | ActiveRecord::Base.establish_connection(ENV["DATABASE_URL"] || YAML.load_file("#{cwd}/config/database.yml")["production"]) 10 | end 11 | 12 | bind 'unix://{{deploy_directory}}/shared/tmp/sockets/puma_{{app_name}}.sock' 13 | environment 'production' 14 | pidfile "{{deploy_directory}}/shared/tmp/puma.pid" 15 | state_path "{{deploy_directory}}/shared/tmp/sockets/puma.state" 16 | 17 | rackup '{{deploy_directory}}/current/config.ru' 18 | 19 | activate_control_app 20 | -------------------------------------------------------------------------------- /vars/defaults.yml: -------------------------------------------------------------------------------- 1 | ## webapp 2 | app_name: cap 3 | webserver_name: cap.hicapacity.org 4 | deploy_directory: /data/{{app_name}} 5 | 6 | ## stolen from https://github.com/jgrowl/ansible-playbook-ruby-from-src 7 | rubyTmpDir: /usr/local/src 8 | rubyUrl: http://cache.ruby-lang.org/pub/ruby/2.1/ruby-2.1.1.tar.gz 9 | rubyCompressedFile: ruby-2.1.1.tar.gz 10 | rubyName: ruby-2.1.1 11 | tmpRubyPath: "{{rubyTmpDir}}/{{rubyName}}" 12 | --------------------------------------------------------------------------------