{"id":18603631,"url":"https://github.com/cogini/ansible-role-elixir-release","last_synced_at":"2025-08-08T04:14:13.880Z","repository":{"id":147373521,"uuid":"134130295","full_name":"cogini/ansible-role-elixir-release","owner":"cogini","description":"Ansible role to deploy an Elixir/Phoenix release using systemd","archived":false,"fork":false,"pushed_at":"2020-02-07T10:28:20.000Z","size":43,"stargazers_count":17,"open_issues_count":0,"forks_count":0,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-04-11T05:39:53.668Z","etag":null,"topics":["ansible","ansible-role","elixir","systemd-unit"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cogini.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2018-05-20T07:51:11.000Z","updated_at":"2023-01-16T07:04:33.000Z","dependencies_parsed_at":null,"dependency_job_id":"1f659c97-2895-4e2f-8026-1b355ff361fe","html_url":"https://github.com/cogini/ansible-role-elixir-release","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/cogini/ansible-role-elixir-release","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cogini%2Fansible-role-elixir-release","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cogini%2Fansible-role-elixir-release/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cogini%2Fansible-role-elixir-release/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cogini%2Fansible-role-elixir-release/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cogini","download_url":"https://codeload.github.com/cogini/ansible-role-elixir-release/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cogini%2Fansible-role-elixir-release/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":269361859,"owners_count":24404435,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-08T02:00:09.200Z","response_time":72,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ansible","ansible-role","elixir","systemd-unit"],"created_at":"2024-11-07T02:14:57.747Z","updated_at":"2025-08-08T04:14:13.872Z","avatar_url":"https://github.com/cogini.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# elixir-release\n\nThis Ansible role deploys Elixir/Phoenix releases.\n\nIt uses Erlang \"releases\" with systemd for process supervision, as described in\n\"[Deploying Elixir apps with Ansible](https://www.cogini.com/blog/deploying-elixir-apps-with-ansible/)\" and.\n\"[Best practices for deploying Elixir apps](https://www.cogini.com/blog/best-practices-for-deploying-elixir-apps/)\".\n\n## Directory structure\n\nIt uses a structure like Capistrano to manage the release files. The base\ndirectory is named for the app, e.g. `/srv/foo`, with a `releases` directory\nunder it.  When the role deploys a release, it creates a directory named by a\ntimestamp, e.g. `/srv/foo/releases/20190603T072116`.  It unpacks the files\nunder it, makes a symlink from `/srv/foo/current` to the new directory.\n\n## Restarting\n\nAfter deploying the release, it restarts the app to make it live.\n\nBy default, when `elixir_release_restart_method: systemctl`, it does this by running:\n\n```shell\nsudo /bin/systemctl restart foo\n```\n\nThe deploy user account needs sufficient permissions to restart the app.\nInstead of giving the deploy account full sudo permissions, a user-specific\nsudo config file specifies what commands it can run, e.g. `/etc/sudoers.d/deploy-foo`:\n\n    deploy ALL=(ALL) NOPASSWD: /bin/systemctl start foo, /bin/systemctl stop foo, /bin/systemctl restart foo\n\nBetter is if we didn't require sudo permissions at all. One option is to take\nadvantage of systemd to restart the app.\n\nSet `elixir_release_restart_method: systemd_flag`, the deploy process touches a\n`/srv/foo/flags/restart.flag` file on the disk after deploying the code.\nSystemd notices and restarts it with the new code.\n\nSee [mix-deploy-example](https://github.com/cogini/mix-deploy-example) for a full example.\n\n# Example Playbook\n\nA minimal playbook, for an app called `foo`:\n\n    - hosts: '*'\n      become: true\n      vars:\n        elixir_release_app_name: foo\n      roles:\n        - cogini.elixir-release\n\nPut this in `ansible/playbooks/deploy-app.yml`.\n\nFirst, set up the target machine, e.g. installing packages and creating directories.\nRun this from your dev machine, specifying a user with sudo permissions:\n\n    ansible-playbook -u $USER -v -l web_servers playbooks/deploy-app.yml --skip-tags deploy -D\n\nNext, deploy the code. Run this from the build server, from a user account with\nssh access to the deploy account on the target machine:\n\n    ansible-playbook -u deploy -v -l web_servers playbooks/deploy-app.yml --tags deploy --extra-vars ansible_become=false -D\n\nA more heaviliy customized playbook:\n\n```yaml\n- hosts: '*'\n  become: true\n  vars:\n    elixir_release_app_name: foo\n    elixir_release_app_user: bar\n    elixir_release_deploy_user: deploy\n    elixir_release_mix_env: frontend\n    # elixir_release_release_name: \"{{ elixir_release_mix_env }}\"\n    # elixir_release_release_system: distillery\n    # elixir_release_start_command: foreground\n    elixir_release_systemd_source: mix_systemd\n    elixir_release_base_dir: /opt/bar\n    elixir_release_app_dirs:\n      - configuration\n      - runtime\n      - logs\n      - tmp\n      - state\n      - cache\n    elixir_release_tmp_directory_base: /var/tmp/bar\n    elixir_release_state_directory_base: /var/bar\n    elixir_release_http_listen_port: 8080\n    elixir_release_cache_directory_mode: 0700\n    elixir_release_configuration_directory_mode: 0755\n    elixir_release_logs_directory_mode: 0755\n    elixir_release_state_directory_mode: 0755\n    elixir_release_tmp_directory_mode: 0755\n    elixir_release_sudoers_file: \"{{ elixir_release_app_user }}-{{ elixir_release_service_name }}\"\n    # Location of source app, assuming that the deploy scripts are in a separate repo in a parallel dir\n    elixir_release_src_dir: \"{{ playbook_dir }}/../../../foo\"\n  roles:\n    - cogini.elixir-release\n```\n\n# Role Variables\n\nSystem used to build releases, either \"mix\" or \"distillery\".\n\n    elixir_release_release_system: \"mix\"\n\nLocation of app to get release files. By default, it assumes that you have an `ansible` directory\nin your app source\n\n    elixir_release_app_dir: \"{{ role_path }}/../../..\"\n\nErlang name of the application, used to by Distillery to name directories\nand scripts.\n\n    elixir_release_app_name: my_app\n\nName of release, by default `app_name`, but often MIX_ENV.\n\n    elixir_release_release_name: \"{{ elixir_release_app_name }}\"\n\nExternal name of the app, used to name the systemd service and directories.\nBy default, it converts underscores to dashes:\n\n    elixir_release_service_name: \"{{ elixir_release_app_name | replace('_', '-') }}\"\n\nElixir application name. By default, it is the CamelCase version of the app name:\n\n    elixir_release_app_module: \"{{ elixir_release_service_name.title().replace('_', '') }}\"\n\nVersion of the app to release. If not specified, will read it from the `start_erl.data`\nfile in the release directory.\n\n    elixir_release_version: \"0.1.0\"\n\nFor security, we use separate accounts to deploy the app and to run it.  The\ndeploy account owns the code and config files, and has rights to restart the\napp. We normally use a separate account called `deploy`.  The app runs under a\nseparate account with the minimum permissions it needs.  We normally create a\nname matching the app, e.g. `foo` or use a generic name like `app`.\n\nThe release files are owned by `deploy:app` with mode 0644 so that the app can read them.\n\nOS account that deploys and owns the release files:\n\n    elixir_release_deploy_user: deploy\n\nOS group that deploys and owns the release files:\n\n    elixir_release_deploy_group: \"{{ elixir_release_deploy_user }}\"\n\nOS account that the app runs under:\n\n    elixir_release_app_user: \"{{ elixir_release_service_name }}\"\n\nOS group that the app runs under:\n\n    elixir_release_app_group: \"{{ elixir_release_app_user }}\"\n\nApp release environment, i.e. the setting of `MIX_ENV`, used to find the release file under the `_build` dir:\n\n    elixir_release_mix_env: prod\n\nDirectory prefix for release files:\n\n    elixir_release_base_dir: /srv\n\nBase directory for deploy files:\n\n    elixir_release_deploy_dir: \"{{ elixir_release_base_dir }}/{{ elixir_release_service_name }}\"\n\nDirectories under deploy dir.\n\nWhere release tarballs are unpacked:\n\n    elixir_release_releases_dir: \"{{ elixir_release_deploy_dir }}/releases\"\n\nCurrently running release (symlink):\n\n    elixir_release_current_dir: \"{{ elixir_release_deploy_dir }}/current\"\n\nLocation of deploy scripts:\n\n    elixir_release_scripts_dir: \"{{ elixir_release_deploy_dir }}/bin\"\n\nFlag file dir, used to signal restart:\n\n    elixir_release_flags_dir: \"{{ elixir_release_deploy_dir }}/flags\"\n\nDirectories where the app keeps its files, following [systemd](https://www.freedesktop.org/software/systemd/man/systemd.exec.html).\n\n    elixir_release_app_dirs:\n      - configuration\n      - runtime\n      # - logs\n      # - tmp\n      # - state\n      # - cache\n\nWhether to use [conform](https://github.com/bitwalker/conform):\n\n    elixir_release_conform: false\n    elixir_release_conform_conf_path: \"{{ elixir_release_configuration_dir }}/config.conform\"\n\nHow we should restart the app:\n\n    elixir_release_restart_method: systemctl\n    # elixir_release_restart_method: systemd_flag\n    # elixir_release_restart_method: touch\n\nOptions are:\n\n* `systemctl`, which runs `systemctl restart foo`\n* `systemd_flag`, which touches the file `{{ elixir_release_shutdown_flags_dir }}/restart.flag`\n* `touch`, which touches the file `{{ elixir_release_shutdown_flags_dir }}/restart.flag`.\n  Directory permissions are 0770, allowing the managed process to restart itself.\n\nWhich users are allowed to restart the app using `sudo /bin/systemctl restart` when method == `systemctl`.\n\n    elixir_release_restart_users:\n        - \"{{ elixir_release_deploy_user }}\"\n\nSet to `[]` and nobody can restart, or add additional names, e.g. `- \"{{ elixir_release_app_user }}\"`.\n\n## systemd and scripts\n\nBy default this role assumes that you are using\n[mix_systemd](https://hex.pm/packages/mix_systemd) to generate the systemd unit\nfile and [mix_deploy](https://hex.pm/packages/mix_deploy) to generate lifecycle\nscripts.\n\n`elixir_release_systemd_source` controls the source of the systemd unit file.\n\n    elixir_release_systemd_source: mix_systemd\n\nWith the default value of `mix_systemd`, the role copies the systemd unit files from the\n`_build/{{ elixir_release_mix_env }}/systemd` directory. Set it to `self`, nd\nthis role will generate a systemd unit file from a template.\n\n`elixir_release_scripts_source` controls the source of the scripts.\n\n    elixir_release_scripts_source: bin\n\nWith the default value of `bin`, the role copies scripts from the project's `bin` directory\nto `/srv/foo/bin` on the target system. Set it to `mix_deploy` if you have set\n`output_dir_per_env: true` in the `mix_deploy` config, storing the generated scripts under `_build`.\n\nThe following variables are used when generating the systemd unit file:\n\nPort that the app listens for HTTP connections on:\n\n    elixir_release_http_listen_port: 4000\n\nPort that the app listens for HTTPS connections on:\n\n    elixir_release_https_listen_port: 4001\n\nOpen file limit:\n\n    elixir_release_limit_nofile: 65536\n\nSeconds to wait between restarts:\n\n    elixir_release_systemd_restart_sec: 5\n\n`LANG` environment var:\n\n    elixir_release_lang: \"en_US.UTF-8\"\n\numask:\n\n    elixir_release_umask: \"0027\"\n\nTarget systemd version, used to enable more advanced features:\n\n    elixir_release_systemd_version: 219\n\nSystemd service type: simple | exec | notify | forking\nSee systemd [Type](https://www.freedesktop.org/software/systemd/man/systemd.service.html#Type=)\n\n    elixir_release_service_type: simple\n\nRelease command to execute to start app. mix uses start for simple, daemon for forking.\ndistilery uses foreground for simple, start for forking.\n\n    elixir_release_start_command: start\n\nPID file when using forking service type:\n\n    elixir_release_pid_file: \"{{ elixir_release_runtime_dir }}/{{ elixir_release_app_name}}.pid\"\n\nList of ExecStartPre scripts in systemd unit file:\n\n    elixir_release_exec_start_pre: []\n\nList of environment vars to set in systemd unit file:\n\n    elixir_release_env_vars: []\n\n# Dependencies\n\nNone\n\n# Requirements\n\nNone\n\n# License\n\nMIT\n\n# Author Information\n\nJake Morrison \u003cjake@cogini.com\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcogini%2Fansible-role-elixir-release","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcogini%2Fansible-role-elixir-release","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcogini%2Fansible-role-elixir-release/lists"}