rails_caddy_dev 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +95 -0
- data/lib/rails_caddy_dev/commands.rb +22 -0
- data/lib/rails_caddy_dev/railtie.rb +13 -0
- data/lib/rails_caddy_dev/railties/available_port.rake +9 -0
- data/lib/rails_caddy_dev/update_config.rb +139 -0
- data/lib/rails_caddy_dev/version.rb +5 -0
- data/lib/rails_caddy_dev.rb +7 -0
- metadata +67 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 6731cf32e6419b5637b8a1764a06e045f6487af31ced9245e61b7c597d560774
|
|
4
|
+
data.tar.gz: '0898b5cc6acc282a396d581934c9f53a308d9387c1ac6027d3be9517b1ea65ad'
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: e1e435b65fd2211860ae00652ea4c5557ae992c490810bcf3975864e965eef2cf98af9d22e8155e74220d8dc6fcfccfc4009eaa24b642bbbc2dca5eb36fc4f4a
|
|
7
|
+
data.tar.gz: ffffa2e702d9d2b30bb394b95965dc44e80ab134a9682ddefb6aeab39d781ee6168c7077db94c9deab802207aa967e96c546ebccb0a6e2455a70405650b074ec
|
data/README.md
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# RailsCaddyDev
|
|
2
|
+
|
|
3
|
+
Automatically configures [Caddy](https://caddyserver.com/) as a local reverse proxy for Rails development. When you start `rails server`, it registers routes via the Caddy admin API so that `<project_name>.localhost` proxies to your locally running Rails server with HTTPS.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- [Caddy](https://caddyserver.com/) installed and running locally
|
|
8
|
+
- Ruby >= 3.1
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
Add it to your application's Gemfile:
|
|
13
|
+
|
|
14
|
+
```ruby
|
|
15
|
+
gem 'rails_caddy_dev', group: :development
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Then run:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
bundle install
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Setup
|
|
25
|
+
|
|
26
|
+
In your application's `bin/rails` file, replace this:
|
|
27
|
+
|
|
28
|
+
```ruby
|
|
29
|
+
require "rails/commands"
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
with this:
|
|
33
|
+
|
|
34
|
+
```ruby
|
|
35
|
+
require "rails_caddy_dev/commands"
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
This will ensure your Caddy configuration is updated each time you start your Rails server in development.
|
|
39
|
+
|
|
40
|
+
## Usage
|
|
41
|
+
|
|
42
|
+
Start your Rails server with the `DEVCADDY` and `PROJECT_NAME` environment variables:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
DEVCADDY=1 PROJECT_NAME=myapp rails server
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
This will configure Caddy to proxy `myapp.localhost` to your Rails server, accessible over HTTPS.
|
|
49
|
+
|
|
50
|
+
### Environment Variables
|
|
51
|
+
|
|
52
|
+
| Variable | Description | Default |
|
|
53
|
+
|---|---|---|
|
|
54
|
+
| `DEVCADDY` | Enables Caddy configuration (must be set) | — |
|
|
55
|
+
| `PROJECT_NAME` | Used to derive the `.localhost` hostname (required) | — |
|
|
56
|
+
| `PORT` | Rails server port to proxy to | `3000` |
|
|
57
|
+
| `CADDY_HOST` | Caddy admin API host | `localhost` |
|
|
58
|
+
| `CADDY_PORT` | Caddy admin API port | `2019` |
|
|
59
|
+
|
|
60
|
+
### Dynamic Port Allocation
|
|
61
|
+
|
|
62
|
+
The gem also provides a CLI command to find an available TCP port, which can be useful if you want to run multiple Rails servers without port conflicts:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
export PORT=$(bundle exec rails rails_caddy_dev:available_port)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
RailsCaddyDev will then configure Caddy to proxy to the dynamically allocated port, and start your Rails server on that port.
|
|
69
|
+
|
|
70
|
+
### Subdomains
|
|
71
|
+
|
|
72
|
+
Subdomains are also supported due to a wildcard Caddy route that will be configured. For example, if you set `PROJECT_NAME=myapp`, then `api.myapp.localhost` will also proxy to your Rails server.
|
|
73
|
+
|
|
74
|
+
### Usage with Mise
|
|
75
|
+
|
|
76
|
+
If you're using [Mise](https://github.com/joelmoss/mise), you can integrate RailsCaddyDev by setting the `PORT` environment variable dynamically using the CLI command provided by RailsCaddyDev. Add this to your Mise config (eg. `mise.toml`):
|
|
77
|
+
|
|
78
|
+
```toml
|
|
79
|
+
[env]
|
|
80
|
+
PORT = { value = "${env.PORT:-{{exec(command='bundle exec rails rails_caddy_dev:available_port')}}}", tools = true }
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Now the `PORT` environment variable will be set to an available port each time you start your Mise environment, allowing you to run multiple Rails servers without port conflicts.
|
|
84
|
+
|
|
85
|
+
## Development
|
|
86
|
+
|
|
87
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bundle exec rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
88
|
+
|
|
89
|
+
## Contributing
|
|
90
|
+
|
|
91
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/joelmoss/rails_caddy_dev.
|
|
92
|
+
|
|
93
|
+
## License
|
|
94
|
+
|
|
95
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This file is responsible for loading the Caddy configuration update logic when the Rails server is
|
|
4
|
+
# started in development mode with the DEVCADDY environment variable set. It should be required from
|
|
5
|
+
# the application's 'bin/rails' file, as a replacement for the default 'require "rails/commands"'
|
|
6
|
+
# line, making it look something like this:
|
|
7
|
+
#
|
|
8
|
+
# #!/usr/bin/env ruby
|
|
9
|
+
#
|
|
10
|
+
# APP_PATH = File.expand_path("../config/application", __dir__)
|
|
11
|
+
# require_relative "../config/boot"
|
|
12
|
+
#
|
|
13
|
+
# # require "rails/commands" # <-- This line should be removed, and replaced with the line below.
|
|
14
|
+
# require "rails_caddy_dev/commands" # <-- This line is added to load the Caddy config logic
|
|
15
|
+
#
|
|
16
|
+
if ENV.fetch('RAILS_ENV', 'development') == 'development' &&
|
|
17
|
+
ENV.key?('DEVCADDY') &&
|
|
18
|
+
%w[s server].include?(ARGV.first)
|
|
19
|
+
require 'rails_caddy_dev/update_config'
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
require 'rails/commands'
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Configures Caddy as a local reverse proxy to your Rails server during development.
|
|
4
|
+
#
|
|
5
|
+
# Uses the Caddy admin API to register a 'route' configuration that proxies requests for
|
|
6
|
+
# `<project_name>.localhost` to the locally running Rails server.
|
|
7
|
+
#
|
|
8
|
+
# This file is intended to be run as part of the `rails server` startup process, and will only
|
|
9
|
+
# execute in the development environment, and when the `DEVCADDY` environment variable is set. It
|
|
10
|
+
# should be required from the application's 'bin/rails' file., making it look something like this:
|
|
11
|
+
#
|
|
12
|
+
# #!/usr/bin/env ruby
|
|
13
|
+
#
|
|
14
|
+
# APP_PATH = File.expand_path("../config/application", __dir__)
|
|
15
|
+
# require_relative "../config/boot"
|
|
16
|
+
#
|
|
17
|
+
# if ENV['RAILS_ENV'] == 'development' && ENV.key?('DEVCADDY') &&
|
|
18
|
+
# (ARGV.first == 's' || ARGV.first == 'server')
|
|
19
|
+
# require 'rails_caddy_dev/update_config'
|
|
20
|
+
# end
|
|
21
|
+
#
|
|
22
|
+
# require "rails/commands"
|
|
23
|
+
#
|
|
24
|
+
#
|
|
25
|
+
# The script checks if a Caddy config for the project already exists by querying the admin API. If
|
|
26
|
+
# it does, it sends a PATCH request to update it; if not, it attempts to append a new route to the
|
|
27
|
+
# existing config or initialize a new config structure if necessary.
|
|
28
|
+
#
|
|
29
|
+
# The script expects the following environment variables:
|
|
30
|
+
# - PROJECT_NAME: Used to derive subdomain hostnames (e.g. "my_project" → my_project.localhost).
|
|
31
|
+
# This is required to ensure unique routing for each project.
|
|
32
|
+
# - PORT: Rails server port (default: 3000)
|
|
33
|
+
# - CADDY_HOST: Caddy admin API host (default: localhost)
|
|
34
|
+
# - CADDY_PORT: Caddy admin API port (default: 2019)
|
|
35
|
+
#
|
|
36
|
+
# If Caddy is not running or the API request fails, the script will print an error message and exit
|
|
37
|
+
# with status 1.
|
|
38
|
+
|
|
39
|
+
require 'net/http'
|
|
40
|
+
require 'json'
|
|
41
|
+
|
|
42
|
+
return if ENV.fetch('RAILS_ENV', 'development') != 'development' || !ENV.key?('DEVCADDY')
|
|
43
|
+
|
|
44
|
+
PORT = ENV.fetch('PORT', '3000')
|
|
45
|
+
CADDY_HOST = ENV.fetch('CADDY_HOST', 'localhost')
|
|
46
|
+
CADDY_PORT = ENV.fetch('CADDY_PORT', '2019').to_i
|
|
47
|
+
PROJECT_NAME = ENV.fetch('PROJECT_NAME')&.downcase
|
|
48
|
+
|
|
49
|
+
domains = [
|
|
50
|
+
"#{PROJECT_NAME}.localhost",
|
|
51
|
+
"admin.#{PROJECT_NAME}.localhost",
|
|
52
|
+
"clients.#{PROJECT_NAME}.localhost",
|
|
53
|
+
"therapists.#{PROJECT_NAME}.localhost"
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
# Check if config already exists via Caddy API
|
|
57
|
+
uri = URI("http://#{CADDY_HOST}:#{CADDY_PORT}/id/#{PROJECT_NAME}")
|
|
58
|
+
config_exists = false
|
|
59
|
+
begin
|
|
60
|
+
response = Net::HTTP.get_response(uri)
|
|
61
|
+
config_exists = response.is_a?(Net::HTTPSuccess)
|
|
62
|
+
rescue Errno::ECONNREFUSED
|
|
63
|
+
puts "⚠️ Caddy admin API not available at #{CADDY_HOST}:#{CADDY_PORT}. Is caddy running?"
|
|
64
|
+
exit 1
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
config = {
|
|
68
|
+
'@id': PROJECT_NAME,
|
|
69
|
+
handle: [
|
|
70
|
+
{
|
|
71
|
+
handler: 'subroute',
|
|
72
|
+
routes: [
|
|
73
|
+
{
|
|
74
|
+
handle: [
|
|
75
|
+
{
|
|
76
|
+
handler: 'reverse_proxy',
|
|
77
|
+
upstreams: [
|
|
78
|
+
{
|
|
79
|
+
dial: ":#{PORT}"
|
|
80
|
+
}
|
|
81
|
+
]
|
|
82
|
+
}
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
]
|
|
86
|
+
}
|
|
87
|
+
],
|
|
88
|
+
match: [
|
|
89
|
+
{
|
|
90
|
+
host: domains
|
|
91
|
+
}
|
|
92
|
+
],
|
|
93
|
+
terminal: true
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
# Caddy admin API
|
|
97
|
+
http = Net::HTTP.new(CADDY_HOST, CADDY_PORT)
|
|
98
|
+
|
|
99
|
+
if config_exists
|
|
100
|
+
# Update existing config via @id endpoint
|
|
101
|
+
request = Net::HTTP::Patch.new("/id/#{PROJECT_NAME}", 'Content-Type' => 'application/json')
|
|
102
|
+
request.body = config.to_json
|
|
103
|
+
action = 'updated'
|
|
104
|
+
else
|
|
105
|
+
# Check if routes path exists, if not initialize the full structure
|
|
106
|
+
routes_uri = URI("http://#{CADDY_HOST}:#{CADDY_PORT}/config/apps/http/servers/srv0/routes")
|
|
107
|
+
routes_response = Net::HTTP.get_response(routes_uri)
|
|
108
|
+
|
|
109
|
+
if routes_response.is_a?(Net::HTTPSuccess)
|
|
110
|
+
# Routes exist, append to them
|
|
111
|
+
request = Net::HTTP::Post.new(routes_uri.path, 'Content-Type' => 'application/json')
|
|
112
|
+
request.body = config.to_json
|
|
113
|
+
else
|
|
114
|
+
# Initialize full config structure
|
|
115
|
+
request = Net::HTTP::Post.new('/config/', 'Content-Type' => 'application/json')
|
|
116
|
+
request.body = {
|
|
117
|
+
apps: {
|
|
118
|
+
http: {
|
|
119
|
+
servers: {
|
|
120
|
+
srv0: {
|
|
121
|
+
listen: [':443'],
|
|
122
|
+
routes: [config]
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}.to_json
|
|
128
|
+
end
|
|
129
|
+
action = 'created'
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
response = http.request(request)
|
|
133
|
+
|
|
134
|
+
if response.is_a?(Net::HTTPSuccess)
|
|
135
|
+
puts "=> Caddy config for '#{PROJECT_NAME}:#{PORT}' #{action}"
|
|
136
|
+
else
|
|
137
|
+
puts "=! Failed to #{action.chomp('d')} Caddy config: #{response.body}"
|
|
138
|
+
exit 1
|
|
139
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: rails_caddy_dev
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Joel Moss
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: rails
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: 7.1.0
|
|
19
|
+
- - "<"
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '9.0'
|
|
22
|
+
type: :runtime
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
25
|
+
requirements:
|
|
26
|
+
- - ">="
|
|
27
|
+
- !ruby/object:Gem::Version
|
|
28
|
+
version: 7.1.0
|
|
29
|
+
- - "<"
|
|
30
|
+
- !ruby/object:Gem::Version
|
|
31
|
+
version: '9.0'
|
|
32
|
+
email:
|
|
33
|
+
- joel@developwithstyle.com
|
|
34
|
+
executables: []
|
|
35
|
+
extensions: []
|
|
36
|
+
extra_rdoc_files: []
|
|
37
|
+
files:
|
|
38
|
+
- README.md
|
|
39
|
+
- lib/rails_caddy_dev.rb
|
|
40
|
+
- lib/rails_caddy_dev/commands.rb
|
|
41
|
+
- lib/rails_caddy_dev/railtie.rb
|
|
42
|
+
- lib/rails_caddy_dev/railties/available_port.rake
|
|
43
|
+
- lib/rails_caddy_dev/update_config.rb
|
|
44
|
+
- lib/rails_caddy_dev/version.rb
|
|
45
|
+
homepage: https://github.com/joelmoss/rails_caddy_dev
|
|
46
|
+
licenses:
|
|
47
|
+
- MIT
|
|
48
|
+
metadata:
|
|
49
|
+
rubygems_mfa_required: 'true'
|
|
50
|
+
rdoc_options: []
|
|
51
|
+
require_paths:
|
|
52
|
+
- lib
|
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
54
|
+
requirements:
|
|
55
|
+
- - ">="
|
|
56
|
+
- !ruby/object:Gem::Version
|
|
57
|
+
version: 3.1.0
|
|
58
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
59
|
+
requirements:
|
|
60
|
+
- - ">="
|
|
61
|
+
- !ruby/object:Gem::Version
|
|
62
|
+
version: '0'
|
|
63
|
+
requirements: []
|
|
64
|
+
rubygems_version: 4.0.3
|
|
65
|
+
specification_version: 4
|
|
66
|
+
summary: Automatic Caddy config for Rails development.
|
|
67
|
+
test_files: []
|