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
sitesx
to your list of dependencies inmix.exs
:
def deps do
[{:sitesx, "~> 0.10"}]
end
- Ensure
sitesx
is 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
end
Mix 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
end
or
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: :digitalocean
hexdocs: 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
end
And 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
end
Create 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
end
Then 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=subdomain2
hexdocs: 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