mcpbeat

Deploy

oliver-kriska/claude-elixir-phoenix-codex-deploy

Elixir/Phoenix deployment patterns — Dockerfile, fly.toml; Use when configuring Fly.io, Docker, CI/CD, health checks…

2k tokens
context cost
the whole folder, loaded on every use
3
files
instructions only
0
copies elsewhere
how many repositories repackaged it
514
stars on the repo
on the repository, not the skill itself

Install

one command, takes just this skill from the repository
npx skills add https://github.com/oliver-kriska/claude-elixir-phoenix --skill deploy

What comes with it

4 641 bytes besides the instruction
references/docker-config.md
references/flyio-config.md

The instruction itself

12 sections, as written by the author

Elixir/Phoenix Deployment Reference

Quick reference for deploying Elixir/Phoenix applications.

Iron Laws — Never Violate These

  • Config at runtime, not compile time — Secrets in config.exs get baked into the release binary. Use runtime.exs with env vars so secrets are resolved at boot
  • Graceful shutdown ≥ 60 seconds — Shorter timeouts kill in-flight requests and WebSocket connections mid-operation, causing data loss for users
  • Health checks required — Without startup/liveness/readiness endpoints, orchestrators can't distinguish a booting node from a dead one, leading to cascading restarts
  • SSL verification for database — Skipping verify: :verify_peer allows MITM attacks between your app and database; production data traverses the connection
  • No CPU limits — The BEAM scheduler assumes it owns all cores; cgroups CPU limits cause scheduler collapse where the VM thinks it has more cores than it can use, leading to latency spikes
  • Guard optional service credentialsruntime.exs runs whenever a

release boots, including eval-based migration commands. Only require S3,

Redis, and similar credentials when that integration is enabled

Quick Configuration

runtime.exs (Essential)

if config_env() == :prod do
  database_url = System.get_env("DATABASE_URL") || raise "DATABASE_URL is required"
  secret_key_base = System.get_env("SECRET_KEY_BASE") || raise "SECRET_KEY_BASE is required"
  host = System.get_env("PHX_HOST") || raise "PHX_HOST is required"

  config :my_app, MyApp.Repo,
    url: database_url,
    pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10"),
    ssl: true,
    ssl_opts: [verify: :verify_peer]

  config :my_app, MyAppWeb.Endpoint,
    url: [host: host, port: 443, scheme: "https"],
    http: [ip: {0, 0, 0, 0}, port: String.to_integer(System.get_env("PORT") || "4000")],
    secret_key_base: secret_key_base,
    server: true
end

Guard Optional Services

Keep core boot secrets such as DATABASE_URL and SECRET_KEY_BASE required.

Gate credentials for optional integrations behind the same feature switch that

enables the integration:

s3_config =
  if System.get_env("STORAGE_BACKEND") == "s3" do
    [
      access_key_id:
        System.get_env("S3_ACCESS_KEY") ||
          raise("S3_ACCESS_KEY is required when STORAGE_BACKEND=s3"),
      secret_access_key:
        System.get_env("S3_SECRET_KEY") ||
          raise("S3_SECRET_KEY is required when STORAGE_BACKEND=s3")
    ]
  else
    []
  end

config :my_app, :s3_config, s3_config

This lets release tasks that do not use S3 start without S3 credentials while

still failing fast when S3 is selected.

Health Check Plug

def call(%{path_info: ["health", "readiness"]} = conn, _opts) do
  case Ecto.Adapters.SQL.query(MyApp.Repo, "SELECT 1", []) do
    {:ok, _} -> send_resp(conn, 200, ~s({"status":"ok"})) |> halt()
    {:error, _} -> send_resp(conn, 503, ~s({"status":"error"})) |> halt()
  end
end

Quick Decisions

Platform Choice

| Need | Use |

|------|-----|

| Simple, managed | Fly.io |

| Enterprise, existing K8s | Kubernetes |

| Custom infrastructure | Docker + your orchestrator |

Resource Limits

| Resource | Recommendation |

|----------|----------------|

| CPU | NO LIMITS (BEAM scheduler issues) |

| Memory | Set limits (256Mi-512Mi typical) |

| Graceful shutdown | ≥ 60 seconds |

Deployment Checklist

  • [ ] All secrets from environment variables in runtime.exs
  • [ ] Optional service credentials required only when their integration is enabled
  • [ ] server: true in endpoint config
  • [ ] SSL verification for database connections
  • [ ] Health endpoints: /health/startup, /health/liveness, /health/readiness
  • [ ] Graceful shutdown period ≥ 60 seconds
  • [ ] No CPU limits (memory limits only)
  • [ ] Migrations in deploy process

Asset Pipeline Notes

Phoenix 1.8 uses esbuild + tailwind (no Node.js required):

  • Config in config/config.exs under :esbuild and :tailwind
  • mix assets.deploy builds for production
  • mix assets.setup installs binaries on first run
  • Custom JS bundlers: configure in config/config.exs

References

For detailed patterns, see:

  • references/docker-config.md - Multi-stage Dockerfile, best practices
  • references/flyio-config.md - fly.toml, clustering, commands

How to use it

Copy the folder

Take oliver-kriska/claude-elixir-phoenix-codex-deploy from the repository into ~/.claude/skills for personal use, or into .claude/skills inside a project.

Check the name does not clash

The agent identifies a skill by the name field in its header. Two skills with the same name cannot sit side by side — one of them will be ignored.