A Phoenix SubDomainer which makes subdomain using DigitalOcean, Cloudflare, etc. API and contains convenient view helper interface along with Plug and Ecto
If available in Hex, the package can be installed as:
- Add
sitesxto your list of dependencies inmix.exs:
def deps do
[{:sitesx, "~> 0.10"}]
end- Ensure
sitesxis started before your application:
def application do
[applications: [:sitesx]]
end- Sitesx needs to add a migration:
defmodule MyApp.Repo.Migrations.CreateSite do
use Ecto.Migration
def change do
create table(:sites) do
add :name, :string
add :dns, :boolean, default: false
timestamps()
end
create index(:sites, [:name], unique: true)
create index(:sites, [:dns])
end
end- After definition, needs to add a model:
defmodule MyApp.Site do
use MyApp.Web, :model
schema "sites" do
field :name, :string
field :dns, :boolean
timestamps()
end
def changeset(struct, params \\ %{}) do
struct
|> cast(params, [:name dns])
|> validate_required([:name])
|> unique_constraint(:name)
end
endMix commands mix sitesx.gen.model or mix sitesx.gen.schema will be able to generate No.3 and No.4 instead of define manually.
$ mix sitesx.gen.model # Until phoenix v1.2.x
$ mix sitesx.gen.schema # Phoenix v1.3.x- Stores Sitesx model into private on Plug struct.
A Sitesx.Plug module extracts domain information from request URL or sub queryparameter.
Plug in Router
defmodule MyApp.Router do
use MyApp.Web, :router
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_flash
plug :protect_from_forgery
plug :put_secure_browser_headers
plug Sitesx.Plug
end
endor
Plug in Controller
defmodule MyApp.MyController do
use MyApp.Web, :controller
plug Sitesx.Plug
end- Configuration
Cloudflare
config :sitesx,
otp_app: MyApp,
domain: "example.com",
ensure_domain_interval: 300,
dns: [
provider: :cloudflare,
auth_email: "mail@example.com",
auth_key: "hash-key1",
zone_identifier: "hash-key1",
]Digitalocean
config :sitesx,
otp_app: MyApp,
domain: "example.com",
request_options: [hackney: [pool: :cloudflare]],
dns: :digitaloceanhexdocs: https://hexdocs.pm/sitesx/Sitesx.App.html
Obviously, those definition are still not enough to work on development. Therefore it will be changed is better that have 1:N relation between one of a model and Site model.
defmodule MyApp.Entry do
use MyApp.Web, :model
schema "entries" do
belongs_to :site, MyApp.Site
field :title, :string
field :content, :string
timestamps()
end
endAnd then
defmodule MyApp.Site do
use MyApp.Web, :model
schema "sites" do
has_many :entries, MyApp.Entry
field :name, :string
field :dns, :boolean
timestamps()
end
endCreate subdomain1 as CNAME record to DNS Provider which will be stored on Cloudflare or Digitalocean. And also will be stores that into database, too.
{_, site} = Sitesx.Q.get_or_create("subdomain1")
Repo.insert_or_update(entry, %{site_id: site.id})Import module
# web/web.ex
defmodule MyApp.Web do
def view do
quote do
use Phoenix.View, root: "web/templates"
...
...
...
import Sitesx.Helpers
end
end
endThen call function
subdomain_url(@conn, "entry.latest")
#-> Ensured domain: http://subdomain1.example.com/entries/latest
#-> Not ensured domain: http://example.com/entries/latest?sub=subdomain1
subdomain_url("subdomain2", @conn, "page.index")
#-> Ensured domain: http://subdomain2.example.com/entries/latest
#-> Not ensured domain: http://example.com/entries/latest?sub=subdomain2hexdocs: https://hexdocs.pm/sitesx/Sitesx.Domain.html
Sitesx.Helpers. Generate URL with subdomain for controller or templates along with Phoenix.HTML.SimplifiedHelpers.URL
hexdocs: https://hexdocs.pm/sitesx/Sitesx.Helpers.html
hexdocs: https://hexdocs.pm/sitesx/Sitesx.Plug.html
hexdocs: https://hexdocs.pm/sitesx/Sitesx.Q.html
hexdocs: https://hexdocs.pm/sitesx/Sitesx.App.html
hexdocs: https://hexdocs.pm/sitesx