| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
I really like how simple it is to manage application processes in production on Heroku with Procfile. How easily you can access application logs with the heroku logs command. Just type heroku create and you're good to go.
Can we have something similar on a cheap Ubuntu VPS from DigitalOcean? Yes we can, all we need is a systemd wrapper that exports application processes from Procfile to system services, and controls them/checks status/accesses logs using simple commands.
These days most Linux distributions (including Ubuntu) have systemd as their default system processes manager. That's why it is a good idea to use systemd for managing application processes in production (for simple cases).
Install procsd first: $ gem install procsd. Required Ruby version is >= 3.2.0.
Let's say you have following application's Procfile:
web: bundle exec rails server -p $PORT
worker: bundle exec sidekiq -e $RAILS_ENVand you want to have one instance of the web process and two instances of the worker process. Create a procsd.yml config file inside the application directory:
app: sample_app
formation: web=1,worker=2
environment:
PORT: 2501
RAILS_ENV: production
RAILS_LOG_TO_STDOUT: trueThe only required option in procsd.yml is app (application name). Also you can provide custom Systemd directory path (systemd_dir option, default is /etc/systemd/system)
Configuration is done.
To disable and remove application from Systemd there is command $ procsd destroy.
deploy@server:~/sample_app$ procsd create Value of the --user option: deploy Value of the --dir option: /home/deploy/sample_app Value of the --path option: /home/deploy/.rbenv/shims:/home/deploy/.rbenv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin Creating app units files in the systemd directory (/etc/systemd/system)... Create: /etc/systemd/system/sample_app-web.1.service Create: /etc/systemd/system/sample_app-worker.1.service Create: /etc/systemd/system/sample_app-worker.2.service Create: /etc/systemd/system/sample_app.target Reloaded configuration (daemon-reload) Created symlink /etc/systemd/system/multi-user.target.wants/sample_app.target → /etc/systemd/system/sample_app.target. Enabled app target sample_app.target App services were created and enabled. Run `start` to start them Note: add following line to the sudoers file (`$ sudo visudo`) if you don't want to type password each time for start/stop/restart commands: deploy ALL=NOPASSWD: /bin/systemctl start sample_app.target, /bin/systemctl stop sample_app.target, /bin/systemctl restart sample_app.target
You can provide additional options for create command:
Other control commands: stop and restart
You can start/stop/restart a particular process by providing its name, e.g.: $ procsd restart worker
deploy@server:~/sample_app$ procsd start Started app services (sample_app.target)
You can filter processes, like $ procsd status worker (show status only for worker processes) or $ procsd status worker.2 (show status only for worker.2 process)
To show status of the main application target: $ procsd status --target
deploy@server:~/sample_app$ procsd status
● sample_app-web.1.service
Loaded: loaded (/etc/systemd/system/sample_app-web.1.service; static; vendor preset: enabled)
Active: active (running) since Sun 2018-11-04 01:54:15 +04; 1min 51s ago
Main PID: 8828 (ruby)
Tasks: 13 (limit: 4915)
Memory: 83.6M
CGroup: /system.slice/sample_app-web.1.service
└─8828 puma 3.12.0 (tcp://0.0.0.0:2500) [sample_app]
2018-11-04T01:54:15+0400 systemd[1]: Started sample_app-web.1.service.
2018-11-04T01:54:17+0400 sample_app-web.1[8828]: => Booting Puma
2018-11-04T01:54:17+0400 sample_app-web.1[8828]: => Rails 5.2.1 application starting in production
2018-11-04T01:54:17+0400 sample_app-web.1[8828]: => Run `rails server -h` for more startup options
2018-11-04T01:54:17+0400 sample_app-web.1[8828]: Puma starting in single mode...
2018-11-04T01:54:17+0400 sample_app-web.1[8828]: * Version 3.12.0 (ruby 2.3.0-p0), codename: Llamas in Pajamas
2018-11-04T01:54:17+0400 sample_app-web.1[8828]: * Min threads: 5, max threads: 5
2018-11-04T01:54:17+0400 sample_app-web.1[8828]: * Environment: production
2018-11-04T01:54:17+0400 sample_app-web.1[8828]: * Listening on tcp://0.0.0.0:2500
2018-11-04T01:54:17+0400 sample_app-web.1[8828]: Use Ctrl-C to stop
● sample_app-worker.1.service
Loaded: loaded (/etc/systemd/system/sample_app-worker.1.service; static; vendor preset: enabled)
Active: active (running) since Sun 2018-11-04 01:54:15 +04; 1min 51s ago
Main PID: 8826 (bundle)
Tasks: 15 (limit: 4915)
Memory: 87.8M
CGroup: /system.slice/sample_app-worker.1.service
└─8826 sidekiq 5.2.2 sample_app [0 of 10 busy]
2018-11-04T01:54:15+0400 systemd[1]: Started sample_app-worker.1.service.
2018-11-04T01:54:17+0400 sample_app-worker.1[8826]: 2018-11-03T21:54:17.655Z 8826 TID-grcvqfyom INFO: Running in ruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-linux]
2018-11-04T01:54:17+0400 sample_app-worker.1[8826]: 2018-11-03T21:54:17.655Z 8826 TID-grcvqfyom INFO: See LICENSE and the LGPL-3.0 for licensing details.
2018-11-04T01:54:17+0400 sample_app-worker.1[8826]: 2018-11-03T21:54:17.655Z 8826 TID-grcvqfyom INFO: Upgrade to Sidekiq Pro for more features and support: http://sidekiq.org
2018-11-04T01:54:17+0400 sample_app-worker.1[8826]: 2018-11-03T21:54:17.655Z 8826 TID-grcvqfyom INFO: Booting Sidekiq 5.2.2 with redis options {:id=>"Sidekiq-serv…, :url=>nil}
2018-11-04T01:54:17+0400 sample_app-worker.1[8826]: 2018-11-03T21:54:17.658Z 8826 TID-grcvqfyom INFO: Starting processing, hit Ctrl-C to stop
● sample_app-worker.2.service
Loaded: loaded (/etc/systemd/system/sample_app-worker.2.service; static; vendor preset: enabled)
Active: active (running) since Sun 2018-11-04 01:54:15 +04; 1min 51s ago
Main PID: 8827 (bundle)
Tasks: 15 (limit: 4915)
Memory: 87.8M
CGroup: /system.slice/sample_app-worker.2.service
└─8827 sidekiq 5.2.2 sample_app [0 of 10 busy]
2018-11-04T01:54:15+0400 systemd[1]: Started sample_app-worker.2.service.
2018-11-04T01:54:17+0400 sample_app-worker.2[8827]: 2018-11-03T21:54:17.713Z 8827 TID-gniahzm1r INFO: Running in ruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-linux]
2018-11-04T01:54:17+0400 sample_app-worker.2[8827]: 2018-11-03T21:54:17.713Z 8827 TID-gniahzm1r INFO: See LICENSE and the LGPL-3.0 for licensing details.
2018-11-04T01:54:17+0400 sample_app-worker.2[8827]: 2018-11-03T21:54:17.714Z 8827 TID-gniahzm1r INFO: Upgrade to Sidekiq Pro for more features and support: http://sidekiq.org
2018-11-04T01:54:17+0400 sample_app-worker.2[8827]: 2018-11-03T21:54:17.714Z 8827 TID-gniahzm1r INFO: Booting Sidekiq 5.2.2 with redis options {:id=>"Sidekiq-serv…, :url=>nil}
2018-11-04T01:54:17+0400 sample_app-worker.2[8827]: 2018-11-03T21:54:17.716Z 8827 TID-gniahzm1r INFO: Starting processing, hit Ctrl-C to stop
Also you can see status in short format:
deploy@server:~/sample_app$ procsd status --short sample_app-web.1.service loaded active running sample_app-web.1.service sample_app-worker.1.service loaded active running sample_app-worker.1.service sample_app-worker.2.service loaded active running sample_app-worker.2.service
Like with command status, you can filter logs by passing the name of process as an argument: $ procsd logs web (show logs only for web processes, if any)
deploy@server:~/sample_app$ procsd logs
-- Logs begin at Sun 2018-10-21 00:38:42 +04, end at Sun 2018-11-04 01:54:17 +04. --
2018-11-04T01:54:15+0400 systemd[1]: Started sample_app-worker.1.service.
2018-11-04T01:54:15+0400 systemd[1]: Started sample_app-worker.2.service.
2018-11-04T01:54:15+0400 systemd[1]: Started sample_app-web.1.service.
2018-11-04T01:54:17+0400 sample_app-worker.1[8826]: 2018-11-03T21:54:17.655Z 8826 TID-grcvqfyom INFO: Running in ruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-linux]
2018-11-04T01:54:17+0400 sample_app-worker.1[8826]: 2018-11-03T21:54:17.655Z 8826 TID-grcvqfyom INFO: See LICENSE and the LGPL-3.0 for licensing details.
2018-11-04T01:54:17+0400 sample_app-worker.1[8826]: 2018-11-03T21:54:17.655Z 8826 TID-grcvqfyom INFO: Upgrade to Sidekiq Pro for more features and support: http://sidekiq.org
2018-11-04T01:54:17+0400 sample_app-worker.1[8826]: 2018-11-03T21:54:17.655Z 8826 TID-grcvqfyom INFO: Booting Sidekiq 5.2.2 with redis options {:id=>"Sidekiq-server-PID-8826", :url=>nil}
2018-11-04T01:54:17+0400 sample_app-worker.1[8826]: 2018-11-03T21:54:17.658Z 8826 TID-grcvqfyom INFO: Starting processing, hit Ctrl-C to stop
2018-11-04T01:54:17+0400 sample_app-worker.2[8827]: 2018-11-03T21:54:17.713Z 8827 TID-gniahzm1r INFO: Running in ruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-linux]
2018-11-04T01:54:17+0400 sample_app-worker.2[8827]: 2018-11-03T21:54:17.713Z 8827 TID-gniahzm1r INFO: See LICENSE and the LGPL-3.0 for licensing details.
2018-11-04T01:54:17+0400 sample_app-worker.2[8827]: 2018-11-03T21:54:17.714Z 8827 TID-gniahzm1r INFO: Upgrade to Sidekiq Pro for more features and support: http://sidekiq.org
2018-11-04T01:54:17+0400 sample_app-worker.2[8827]: 2018-11-03T21:54:17.714Z 8827 TID-gniahzm1r INFO: Booting Sidekiq 5.2.2 with redis options {:id=>"Sidekiq-server-PID-8827", :url=>nil}
2018-11-04T01:54:17+0400 sample_app-worker.2[8827]: 2018-11-03T21:54:17.716Z 8827 TID-gniahzm1r INFO: Starting processing, hit Ctrl-C to stop
2018-11-04T01:54:17+0400 sample_app-web.1[8828]: => Booting Puma
2018-11-04T01:54:17+0400 sample_app-web.1[8828]: => Rails 5.2.1 application starting in production
2018-11-04T01:54:17+0400 sample_app-web.1[8828]: => Run `rails server -h` for more startup options
2018-11-04T01:54:17+0400 sample_app-web.1[8828]: Puma starting in single mode...
2018-11-04T01:54:17+0400 sample_app-web.1[8828]: * Version 3.12.0 (ruby 2.3.0-p0), codename: Llamas in Pajamas
2018-11-04T01:54:17+0400 sample_app-web.1[8828]: * Min threads: 5, max threads: 5
2018-11-04T01:54:17+0400 sample_app-web.1[8828]: * Environment: production
2018-11-04T01:54:17+0400 sample_app-web.1[8828]: * Listening on tcp://0.0.0.0:2500
2018-11-04T01:54:17+0400 sample_app-web.1[8828]: Use Ctrl-C to stop
Systemd provides a lot of possibilities to display and manage application logs (journalctl command). Procsd supports following options:
Currently, procsd can not run all processes in development like foreman start does. But you can run one single process using procsd exec command:
deploy@server:~/sample_app$ procsd exec web => Booting Puma => Rails 5.2.1 application starting in production => Run `rails server -h` for more startup options Puma starting in single mode... * Version 3.12.0 (ruby 2.3.0-p0), codename: Llamas in Pajamas * Min threads: 5, max threads: 5 * Environment: production * Listening on tcp://localhost:2501 Use Ctrl-C to stop
procsd exec requires all the environment variables defined in environment section of procsd.yml config file.
Sometimes in development mode you need different environment configuration. For that you can add additional environment section dev_environment and require it as well using --dev flag, example:
app: sample_app
environment:
PORT: 2501
RAILS_ENV: production
RAILS_LOG_TO_STDOUT: true
dev_environment:
RAILS_ENV: development
SOME_OTHER_DEV_ENV_VARIABLE: value# Run web process with all environment & dev_environment variables included: deploy@server:~/sample_app$ procsd exec web --dev
If dev_environment has an env variable with the same name as one in environment, it will be overwritten with the value from dev_environment.
First, make sure that you have Nginx installed (sudo apt install nginx) and running (sudo systemctl status nginx).
If one of your application processes is a web process, you can automatically set up an Nginx (reverse proxy) config for it. Why? For example, to serve static files (assets, images, and all other files located in public folder or another custom folder) directly using Nginx, rather than the application server. Or to enable SSL support (see below).
Add to your procsd.yml nginx section with server_name option defined:
If you don't have a domain for an application (or don't need it), you can add server IP instead: server_name: 159.159.159.159.
If your application use multiple domains/subdomains, add all of them separated with space: server_name: my-domain.com us.my-domain.com uk.my-domain.com
app: sample_app
processes:
web: bundle exec rails server -p $PORT
worker: bundle exec sidekiq -e $RAILS_ENV
formation: web=1,worker=2
environment:
PORT: 2501 # PORT will be used by Nginx to proxy requests from 0.0.0.0:80/443 to 127.0.0.1:PORT (required)
HOST: localhost # Make sure that your application server in production running on 127.0.0.1, not 0.0.0.0
RAILS_ENV: production
RAILS_LOG_TO_STDOUT: true
nginx:
server_name: my-domain.com
public_folder_path: public # path is relative to the main project directory, default value is `public`.Configuration is done! Run procsd create to create app services with Nginx reverse proxy config:
deploy@server:~/sample_app$ procsd create Creating app units files in the systemd directory (/etc/systemd/system)... Create: /etc/systemd/system/sample_app-web.1.service Create: /etc/systemd/system/sample_app-worker.1.service Create: /etc/systemd/system/sample_app-worker.2.service Create: /etc/systemd/system/sample_app.target Reloaded configuration (daemon-reload) Created symlink /etc/systemd/system/multi-user.target.wants/sample_app.target → /etc/systemd/system/sample_app.target. Enabled app target sample_app.target App services were created and enabled. Run `start` to start them Creating Nginx config (/etc/nginx/sites-available/sample_app)... Create: /etc/nginx/sites-available/sample_app Link Nginx config file to the sites-enabled folder... Nginx config created and daemon reloaded
upstream sample_app {
server 127.0.0.1:2501;
}
server {
listen 80;
listen [::]:80;
server_name my-domain.com;
root /home/deploy/sample_app/public;
location ^~ /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
try_files $uri/index.html $uri @sample_app;
location @sample_app {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_redirect off;
proxy_pass http://sample_app;
}
client_max_body_size 256M;
keepalive_timeout 60;
error_page 500 502 503 504 /500.html;
error_page 404 /404.html;
error_page 422 /422.html;
}
Everything is done. Start app services (procsd start) and go to http://my-domain.com where you'll see your application proxying with Nginx.
To generate Nginx config with free SSL certificate (from Let’s Encrypt) included, you need to install Certbot on the remote server first. For Ubuntu (check here instructions for other versions https://certbot.eff.org/instructions?ws=nginx&os=snap):
$ sudo snap install --classic certbot
$ sudo ln -s /snap/bin/certbot /usr/local/bin/certbotWhen you install certbot, it automatically setup a cron job (twice per day) to renew expiring certificates (Automated Renewals), so you don't have to worry about renewing certificates manually.
Then update procsd.yml by adding ssl: true:
# ...
nginx:
server_name: my-domain.com
ssl: true # addedConfiguration is done. Make sure that all domains defined in procsd (nginx.server_name) are pointing to the server IP where application is hosted. Then run procsd create (you will probably need first run procsd destroy if app services already exists) as usual:
OutputBy default Certbot obtaining certificate from Let's Encrypt without a contact email. If you want to provide contact email, define env variable CERTBOT_EMAIL with your email in the .env file.
deploy@server:~/sample_app$ procsd create Creating app units files in the systemd directory (/etc/systemd/system)... Create: /etc/systemd/system/sample_app-web.1.service Create: /etc/systemd/system/sample_app-worker.1.service Create: /etc/systemd/system/sample_app-worker.2.service Create: /etc/systemd/system/sample_app.target Reloaded configuration (daemon-reload) Created symlink /etc/systemd/system/multi-user.target.wants/sample_app.target → /etc/systemd/system/sample_app.target. Enabled app target sample_app.target App services were created and enabled. Run `start` to start them Creating Nginx config (/etc/nginx/sites-available/sample_app)... Create: /etc/nginx/sites-available/sample_app Link Nginx config file to the sites-enabled folder... Nginx config created and daemon reloaded Execute: sudo certbot --agree-tos --no-eff-email --non-interactive --nginx -d my-domain.com --register-unsafely-without-email Saving debug log to /var/log/letsencrypt/letsencrypt.log Plugins selected: Authenticator nginx, Installer nginx Obtaining a new certificate Performing the following challenges: http-01 challenge for my-domain.com Waiting for verification... Cleaning up challenges Deploying Certificate to VirtualHost /etc/nginx/sites-enabled/sample_app Redirecting all traffic on port 80 to ssl in /etc/nginx/sites-enabled/sample_app - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Congratulations! You have successfully enabled https://my-domain.com You should test your configuration at: https://www.ssllabs.com/ssltest/analyze.html?d=my-domain.com - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at: /etc/letsencrypt/live/my-domain.com/fullchain.pem Your key file has been saved at: /etc/letsencrypt/live/my-domain.com/privkey.pem Your cert will expire on 2019-02-17. To obtain a new or tweaked version of this certificate in the future, simply run certbot again with the "certonly" option. To non-interactively renew *all* of your certificates, run "certbot renew" - Your account credentials have been saved in your Certbot configuration directory at /etc/letsencrypt. You should make a secure backup of this folder now. This configuration directory will also contain certificates and private keys obtained by Certbot so making regular backups of this folder is ideal. - If you like Certbot, please consider supporting our work by: Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate Donating to EFF: https://eff.org/donate-le Successfully installed SSL cert using certbot
That's it. Start app services (procsd start) and go to https://my-domain.com where you'll see your application proxying with Nginx and SSL enabled.
Note about using Cloudflare CDNIf you use Cloudflare CDN, that means the process of obtaining Let's Encrypt SSL Certificate will fail. To fix it, install python-certbot-dns-cloudflare package:
$ sudo apt install certbot python-certbot-dns-cloudflareRead instructions here how to get Cloudflare API Token and obtain certificates. In short,
1) Go to https://dash.cloudflare.com/profile/api-tokens and get your API Token.
2) Create on the server ~/.secrets/certbot/ directory with cloudflare.ini file inside:
$ mkdir -p ~/.secrets/certbot/
$ chmod 0700 ~/.secrets/
$ touch ~/.secrets/certbot/cloudflare.ini
$ chmod 0400 ~/.secrets/certbot/cloudflare.ini3) Put inside cloudflare.ini file your Cloudflare token:
$ sudo nano ~/.secrets/certbot/cloudflare.ini# ~/.secrets/certbot/cloudflare.ini
# Cloudflare API token (example) used by Certbot:
dns_cloudflare_api_token = 0123456789abcdef0123456789abcdef012345674) Obtain certificates for all your domains declared in procsd.yml using certbot-dns-cloudflare plugin:
# Example command for my-domain.com domain:
$ sudo certbot certonly --dns-cloudflare --dns-cloudflare-credentials ~/.secrets/certbot/cloudflare.ini -d my-domain.com5) If all went fine, update Nginx application config with new certificates (using certbot command). To get required certbot command type $ procsd config certbot_command, then execute it:
# Example command for my-domain.com domain:
$ sudo certbot --agree-tos --no-eff-email --redirect --non-interactive --nginx -d my-domain.com --register-unsafely-without-emailAll is done!
$ procsd --help Commands: procsd create # Create and enable app services procsd destroy # Stop, disable and remove app services procsd start # Start app services procsd stop # Stop app services procsd restart # Restart app services procsd enable # Enable app target procsd disable # Disable app target procsd logs # Show app services logs procsd status # Show app services status procsd list # List all app services procsd exec # Run single app process with environment procsd config # Print config files based on current settings. Available types: sudoers, services, certbot_command procsd help [COMMAND] # Describe available commands or one specific command procsd --version, -v # Print the version
Foreman itself is designed for development (not production) usage only and does it great. Yes, Foreman allows you to export Procfile to Systemd, but that's all. After export you have to manually use systemctl and journalctl to manage/check exported services. Procsd not only exports the application, but provides simple commands to manage the exported target.
Foreman systemd export uses dynamic services templates and as a result generates quite a lot of files/folders in the systemd directory even for a simple application.
Services generated using Foreman contain the $PORT variable in their names (and it's undocumented logic). For example, for Procfile and formation web=1,worker=2 (from the example above), exported services with Foreman will be: sample_app-web@2500.service, sample_app-worker@2600.service and sample_app-worker@2601.service. My opinion about this approach: it's complicated. Why is the PORT variable required in the service names? Procsd follows one rule: simplicity. For export it uses static service files (that means for each process its own service file will be generated) and service names are predictable, Heroku-like.
Procsd export can provide additional stop/restart commands for each service (see Notes below).
To delete existing app services from Systemd, there is the procsd destroy command. It does the following: stops services if they are running, deletes all required systemd files from the systemd directory, and restarts systemd (daemon-reload). This command is especially useful while testing, when you need to frequently create/update configuration.
If you want to set environment variables per process, use format like Foreman recommends.
To print commands before execution, provide env variable VERBOSE=true before procsd command. Example:
deploy@server:~/sample_app$ VERBOSE=true procsd logs -n 3
Execute: journalctl --no-pager --no-hostname --all --output short-iso -n 3 --unit sample_app-*
-- Logs begin at Sun 2018-10-21 00:38:42 +04, end at Sun 2018-11-04 19:17:01 +04. --
2018-11-04T19:11:59+0400 sample_app-worker.2[29907]: 2018-11-04T15:11:59.597Z 29907 TID-gne5aeyuz INFO: Upgrade to Sidekiq Pro for more features and support: http://sidekiq.org
2018-11-04T19:11:59+0400 sample_app-worker.2[29907]: 2018-11-04T15:11:59.597Z 29907 TID-gne5aeyuz INFO: Booting Sidekiq 5.2.2 with redis options {:id=>"Sidekiq-server-PID-29907", :url=>nil}
2018-11-04T19:11:59+0400 sample_app-worker.2[29907]: 2018-11-04T15:11:59.601Z 29907 TID-gne5aeyuz INFO: Starting processing, hit Ctrl-C to stop
All possible options: ExecStart (default command to start a process), ExecReload, and ExecStop.
If procsd.yml has processes: option defined, then content of Procfile (if it exists) will be ignored.
app: sample_app
processes:
web:
ExecStart: bundle exec rails server -p $PORT
ExecReload: bundle exec pumactl phased-restart
worker: bundle exec sidekiq -e productionWhy? For example default Ruby on Rails application server Puma supports Phased or Rolling restart feature. If you provide separate ExecReloadcommand for a process, then this command will be called while executing $ procsd restart by systemd instead of just killing and starting process again.
Example values for RuntimeMaxSec: 30s (30 seconds), 5m (5 minutes), 3h (3 hours), 1d (1 day).
app: sample_app
processes:
web:
ExecStart: bundle exec rails server -p $PORT
RuntimeMaxSec: 12hhttps://github.com/vifreefly/capistrano-procsd
The gem is available as open source under the terms of the MIT License.
| Back | FazBrowse Home | New Git URL |