Skip to content

Commit eb22654

Browse files
SteveLTNserg-bloimWeiyan
authoredMar 15, 2025
Implement support for different port configuration (#376)
* Support for ports different from 443. It allows to do configurations like: environment: DOMAINS: > myserver.example.com:1443 -> http://localhost:8081, myserver.example.com:2443 -> http://localhost:8082 * Add tests for the new port configuration * Do certificate signing only on unique domains * Update documentation * Bump version to 1.25.0 --------- Co-authored-by: serg-bloim <serg.bloim@gmail.com> Co-authored-by: Weiyan <steve.wy.shao@gmail.com>
1 parent fbb2ec9 commit eb22654

File tree

8 files changed

+66
-35
lines changed

8 files changed

+66
-35
lines changed
 

‎README.md

+20
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ Thanks to [@yamada28go](https://github.com/yamada28go), there is a [Japanese ver
2727
- [Automatic Container Discovery](#automatic-container-discovery)
2828
- [Hybrid Setup with Non-Dockerized Apps](#hybrid-setup-with-non-dockerized-apps)
2929
- [Multiple Domains](#multiple-domains)
30+
- [Custom Ports](#custom-ports)
3031
- [Multiple Upstreams](#multiple-upstreams)
3132
- [Serving Static Sites](#serving-static-sites)
3233
- [Share Certificates with Other Apps](#share-certificates-with-other-apps)
@@ -319,6 +320,25 @@ https-portal:
319320

320321
It will make reading and managing multiple domains easier.
321322

323+
### Custom Ports
324+
325+
Due to Let's Encrypt's constraints, Port 80 must be used for verifying the domian. But you can use a different port than 443 for SSL traffic.
326+
327+
```yaml
328+
https-portal:
329+
# ...
330+
ports:
331+
- '80:80'
332+
- '4343:4343' # Make sure to add the other ports you want to listen to
333+
- '443:443'
334+
environment:
335+
# You can combine the same domain with different ports.
336+
DOMAINS: >
337+
wordpress.example.com:4343 -> http://wordpress:80,
338+
wordpress.example.com:443 -> http://gitlab:80,
339+
OTHER_VARS: ...
340+
```
341+
322342
### Multiple Upstreams
323343

324344
It's possible to define multiple upstreams for a domain for the purpose of load-balancing and/or HA.

‎fs_overlay/etc/cont-init.d/00-welcome

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22

33
echo '
44
========================================
5-
HTTPS-PORTAL v1.24.2
5+
HTTPS-PORTAL v1.25.0
66
========================================
77
'

‎fs_overlay/opt/certs_manager/certs_manager.rb

+4-4
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def setup_config(initial)
4343
Nginx.reload
4444
end
4545

46-
ensure_signed(NAConfig.domains, true)
46+
ensure_signed(NAConfig.domains_w_unique_names, true)
4747

4848
if initial
4949
Nginx.stop
@@ -60,7 +60,7 @@ def renew
6060
puts "Renewing ..."
6161
NAConfig.domains.each(&:print_debug_info) if NAConfig.debug_mode?
6262
with_lock do
63-
NAConfig.domains.each do |domain|
63+
NAConfig.domains_w_unique_names.each do |domain|
6464
if NAConfig.debug_mode?
6565
domain.print_debug_info
6666
end
@@ -106,9 +106,9 @@ def ensure_keys_and_certs_exist(domains)
106106
end
107107
end
108108

109-
def ensure_signed(domains, exit_on_failure = false)
109+
def ensure_signed(domains_w_unique_names, exit_on_failure = false)
110110
Logger.debug ("ensure_signed")
111-
domains.each do |domain|
111+
domains_w_unique_names.each do |domain|
112112
if OpenSSL.need_to_sign_or_renew? domain
113113
mkdir(domain)
114114
OpenSSL.create_ongoing_domain_key(domain)

‎fs_overlay/opt/certs_manager/lib/na_config.rb

+4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ def self.portal_base_dir
44
end
55

66
def self.domains
7+
(env_domains + auto_discovered_domains).uniq {|d| [d.name, d.port] }
8+
end
9+
10+
def self.domains_w_unique_names
711
(env_domains + auto_discovered_domains).uniq(&:name)
812
end
913

‎fs_overlay/opt/certs_manager/lib/nginx.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def self.config_http(domain)
1818
end
1919

2020
def self.config_ssl(domain)
21-
File.open("/etc/nginx/conf.d/#{domain.name}.ssl.conf", 'w') do |f|
21+
File.open("/etc/nginx/conf.d/#{domain.name}_#{domain.port}.ssl.conf", 'w') do |f|
2222
f.write compiled_domain_config(domain, true)
2323
end
2424
end

‎fs_overlay/opt/certs_manager/models/domain.rb

+6-1
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,10 @@ def name
7777
parsed_descriptor[:domain]
7878
end
7979

80+
def port
81+
parsed_descriptor[:port] || '443'
82+
end
83+
8084
def env_format_name
8185
name.upcase.tr('^A-Z0-9', '_')
8286
end
@@ -166,6 +170,7 @@ def access_restriction
166170
def print_debug_info
167171
puts "----------- BEGIN DOMAIN CONFIG -------------"
168172
puts "name: #{name}"
173+
puts "port: #{port}"
169174
puts "stage: #{stage}"
170175
puts "upstream: #{upstream}"
171176
puts "upstreams: #{upstreams.inspect}"
@@ -190,7 +195,7 @@ def parsed_descriptor
190195
regex = %r{
191196
^
192197
(?:\[(?<ips>[0-9.:\/, ]*)\]\s*)?
193-
(?:(?<user>[^:@\[\]]+)(?::(?<pass>[^@]*))?@)?(?<domain>[a-z0-9._\-]+?)
198+
(?:(?<user>[^:@\[\]]+)(?::(?<pass>[^@]*))?@)?(?<domain>[a-z0-9._\-]+?)(?:\:(?<port>\d+))?
194199
(?:
195200
\s*(?<mode>[-=]>)\s*
196201
(?<upstream_proto>https?:\/\/)?

‎fs_overlay/var/lib/nginx-conf/default.ssl.conf.erb

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ upstream <%= domain.upstream_backend_name %> {
77
<% end %>
88

99
server {
10-
listen 443 ssl;
10+
listen <%= domain.port %> ssl;
1111
<% if ENV['LISTEN_IPV6'] && ENV['LISTEN_IPV6'].downcase == 'true' %>
12-
listen [::]:443 ssl;
12+
listen [::]:<%= domain.port %> ssl;
1313
<% end %>
1414
http2 on;
1515

‎spec/models/domain_spec.rb

+28-26
Original file line numberDiff line numberDiff line change
@@ -8,34 +8,35 @@
88
end
99

1010
it 'returns correct names, upstream. redirect_target_url, stage etc.' do
11-
keys = [:descriptor, :name, :env_format_name, :upstream_proto, :upstreams, :redirect_target_url, :stage, :basic_auth_username, :basic_auth_password, :access_restriction]
11+
keys = [:descriptor, :name, :env_format_name, :upstream_proto, :upstreams, :redirect_target_url, :stage, :basic_auth_username, :basic_auth_password, :access_restriction, :port]
1212

1313
domain_configs = [
14-
['example.com', 'example.com', 'EXAMPLE_COM', nil, [], nil, 'local', nil, nil, nil],
15-
['4example.com', '4example.com', '4EXAMPLE_COM', nil, [], nil, 'local', nil, nil, nil],
16-
[' example.com ', 'example.com', 'EXAMPLE_COM', nil, [], nil, 'local', nil, nil, nil],
17-
['example.com #staging', 'example.com', 'EXAMPLE_COM', nil, [], nil, 'staging', nil, nil, nil],
18-
['example.com -> http://target ', 'example.com', 'EXAMPLE_COM', 'http://', [{:address => 'target', :parameters => nil}], nil, 'local', nil, nil, nil],
19-
["example.com \n-> http://target \n", 'example.com', 'EXAMPLE_COM', 'http://', [{:address => 'target', :parameters => nil}], nil, 'local', nil, nil, nil],
20-
["example.com\n-> http://target ", 'example.com', 'EXAMPLE_COM', 'http://', [{:address => 'target', :parameters => nil}], nil, 'local', nil, nil, nil],
21-
['example.com -> http://target:8000', 'example.com', 'EXAMPLE_COM', 'http://', [{:address => 'target:8000', :parameters => nil}], nil, 'local', nil, nil, nil],
22-
['example.com -> target:8000', 'example.com', 'EXAMPLE_COM', 'http://', [{:address => 'target:8000', :parameters => nil}], nil, 'local', nil, nil, nil],
23-
['example.com => http://target', 'example.com', 'EXAMPLE_COM', 'http://', [{:address => 'target', :parameters => nil}], 'http://target', 'local', nil, nil, nil],
24-
['example.com => https://target', 'example.com', 'EXAMPLE_COM', 'https://', [{:address => 'target', :parameters => nil}], 'https://target', 'local', nil, nil, nil],
25-
['example.com => target', 'example.com', 'EXAMPLE_COM', 'https://', [{:address => 'target', :parameters => nil}], 'https://target', 'local', nil, nil, nil],
26-
['example.com=>http://target', 'example.com', 'EXAMPLE_COM', 'http://', [{:address => 'target', :parameters => nil}], 'http://target', 'local', nil, nil, nil],
27-
['example.com -> http://target #staging', 'example.com', 'EXAMPLE_COM', 'http://', [{:address => 'target', :parameters => nil}], nil, 'staging', nil, nil, nil],
28-
['example.com => http://target #staging', 'example.com', 'EXAMPLE_COM', 'http://', [{:address => 'target', :parameters => nil}], 'http://target', 'staging', nil, nil, nil],
29-
['example.com->http://target #staging', 'example.com', 'EXAMPLE_COM', 'http://', [{:address => 'target', :parameters => nil}], nil, 'staging', nil, nil, nil],
30-
['exam-ple.com->http://tar-get #staging', 'exam-ple.com', 'EXAM_PLE_COM', 'http://', [{:address => 'tar-get', :parameters => nil}], nil, 'staging', nil, nil, nil],
31-
['example_.com->http://target #staging', 'example_.com', 'EXAMPLE__COM', 'http://', [{:address => 'target', :parameters => nil}], nil, 'staging', nil, nil, nil],
32-
['example.com->http://tar_get_ #staging', 'example.com', 'EXAMPLE_COM', 'http://', [{:address => 'tar_get_', :parameters => nil}], nil, 'staging', nil, nil, nil],
33-
['username:password@example.com', 'example.com', 'EXAMPLE_COM', nil, [], nil, 'local', 'username', 'password', nil],
34-
['username:password@example.com -> http://target #staging', 'example.com', 'EXAMPLE_COM', 'http://', [{:address => 'target', :parameters => nil}], nil, 'staging', 'username', 'password', nil],
35-
['[1.2.3.4/24]username:password@example.com -> http://target #staging', 'example.com', 'EXAMPLE_COM', 'http://', [{:address => 'target', :parameters => nil}], nil, 'staging', 'username', 'password', %w(1.2.3.4/24)],
36-
[' [ 1.2.3.4 4.3.2.1/24 ] username:password@example.com -> http://target #staging', 'example.com', 'EXAMPLE_COM', 'http://', [{:address => 'target', :parameters => nil}], nil, 'staging', 'username', 'password', %w(1.2.3.4 4.3.2.1/24)],
37-
['example.com -> https://target1|target2:8000', 'example.com', 'EXAMPLE_COM', 'https://', [{:address => 'target1', :parameters => nil}, {:address => 'target2:8000', :parameters => nil}], nil, 'local', nil, nil, nil],
38-
['example.com -> http://target1:8000|target2:8001[backup max_conns=100]', 'example.com', 'EXAMPLE_COM', 'http://', [{:address => 'target1:8000', :parameters => nil}, {:address => 'target2:8001', :parameters => 'backup max_conns=100'}], nil, 'local', nil, nil, nil],
14+
['example.com', 'example.com', 'EXAMPLE_COM', nil, [], nil, 'local', nil, nil, nil, "443"],
15+
['example.com:4443', 'example.com', 'EXAMPLE_COM', nil, [], nil, 'local', nil, nil, nil, "4443"],
16+
['4example.com', '4example.com', '4EXAMPLE_COM', nil, [], nil, 'local', nil, nil, nil, "443"],
17+
[' example.com ', 'example.com', 'EXAMPLE_COM', nil, [], nil, 'local', nil, nil, nil, "443"],
18+
['example.com #staging', 'example.com', 'EXAMPLE_COM', nil, [], nil, 'staging', nil, nil, nil, "443"],
19+
['example.com -> http://target ', 'example.com', 'EXAMPLE_COM', 'http://', [{:address => 'target', :parameters => nil}], nil, 'local', nil, nil, nil, "443"],
20+
["example.com \n-> http://target \n", 'example.com', 'EXAMPLE_COM', 'http://', [{:address => 'target', :parameters => nil}], nil, 'local', nil, nil, nil, "443"],
21+
["example.com\n-> http://target ", 'example.com', 'EXAMPLE_COM', 'http://', [{:address => 'target', :parameters => nil}], nil, 'local', nil, nil, nil, "443"],
22+
['example.com -> http://target:8000', 'example.com', 'EXAMPLE_COM', 'http://', [{:address => 'target:8000', :parameters => nil}], nil, 'local', nil, nil, nil, "443"],
23+
['example.com -> target:8000', 'example.com', 'EXAMPLE_COM', 'http://', [{:address => 'target:8000', :parameters => nil}], nil, 'local', nil, nil, nil, "443"],
24+
['example.com => http://target', 'example.com', 'EXAMPLE_COM', 'http://', [{:address => 'target', :parameters => nil}], 'http://target', 'local', nil, nil, nil, "443"],
25+
['example.com => https://target', 'example.com', 'EXAMPLE_COM', 'https://', [{:address => 'target', :parameters => nil}], 'https://target', 'local', nil, nil, nil, "443"],
26+
['example.com => target', 'example.com', 'EXAMPLE_COM', 'https://', [{:address => 'target', :parameters => nil}], 'https://target', 'local', nil, nil, nil, "443"],
27+
['example.com=>http://target', 'example.com', 'EXAMPLE_COM', 'http://', [{:address => 'target', :parameters => nil}], 'http://target', 'local', nil, nil, nil, "443"],
28+
['example.com -> http://target #staging', 'example.com', 'EXAMPLE_COM', 'http://', [{:address => 'target', :parameters => nil}], nil, 'staging', nil, nil, nil, "443"],
29+
['example.com => http://target #staging', 'example.com', 'EXAMPLE_COM', 'http://', [{:address => 'target', :parameters => nil}], 'http://target', 'staging', nil, nil, nil, "443"],
30+
['example.com->http://target #staging', 'example.com', 'EXAMPLE_COM', 'http://', [{:address => 'target', :parameters => nil}], nil, 'staging', nil, nil, nil, "443"],
31+
['exam-ple.com->http://tar-get #staging', 'exam-ple.com', 'EXAM_PLE_COM', 'http://', [{:address => 'tar-get', :parameters => nil}], nil, 'staging', nil, nil, nil, "443"],
32+
['example_.com->http://target #staging', 'example_.com', 'EXAMPLE__COM', 'http://', [{:address => 'target', :parameters => nil}], nil, 'staging', nil, nil, nil, "443"],
33+
['example.com->http://tar_get_ #staging', 'example.com', 'EXAMPLE_COM', 'http://', [{:address => 'tar_get_', :parameters => nil}], nil, 'staging', nil, nil, nil, "443"],
34+
['username:password@example.com', 'example.com', 'EXAMPLE_COM', nil, [], nil, 'local', 'username', 'password', nil, "443"],
35+
['username:password@example.com -> http://target #staging', 'example.com', 'EXAMPLE_COM', 'http://', [{:address => 'target', :parameters => nil}], nil, 'staging', 'username', 'password', nil, "443"],
36+
['[1.2.3.4/24]username:password@example.com -> http://target #staging', 'example.com', 'EXAMPLE_COM', 'http://', [{:address => 'target', :parameters => nil}], nil, 'staging', 'username', 'password', %w(1.2.3.4/24), "443"],
37+
[' [ 1.2.3.4 4.3.2.1/24 ] username:password@example.com -> http://target #staging', 'example.com', 'EXAMPLE_COM', 'http://', [{:address => 'target', :parameters => nil}], nil, 'staging', 'username', 'password', %w(1.2.3.4 4.3.2.1/24), "443"],
38+
['example.com -> https://target1|target2:8000', 'example.com', 'EXAMPLE_COM', 'https://', [{:address => 'target1', :parameters => nil}, {:address => 'target2:8000', :parameters => nil}], nil, 'local', nil, nil, nil, "443"],
39+
['example.com -> http://target1:8000|target2:8001[backup max_conns=100]', 'example.com', 'EXAMPLE_COM', 'http://', [{:address => 'target1:8000', :parameters => nil}, {:address => 'target2:8001', :parameters => 'backup max_conns=100'}], nil, 'local', nil, nil, nil, "443"],
3940
]
4041

4142
domain_configs.map { |config|
@@ -52,6 +53,7 @@
5253
expect(domain.basic_auth_username).to eq(config[:basic_auth_username]), lambda { "Parsing failed on #{config[:descriptor].inspect} method :basic_auth_username, expected #{config[:basic_auth_username].inspect}, got #{domain.basic_auth_username.inspect}" }
5354
expect(domain.basic_auth_password).to eq(config[:basic_auth_password]), lambda { "Parsing failed on #{config[:descriptor].inspect} method :basic_auth_password, expected #{config[:basic_auth_password].inspect}, got #{domain.basic_auth_password.inspect}" }
5455
expect(domain.access_restriction).to eq(config[:access_restriction]), lambda { "Parsing failed on #{config[:descriptor].inspect} method :access_restriction, expected #{config[:access_restriction].inspect}, got #{domain.access_restriction.inspect}" }
56+
expect(domain.port).to eq(config[:port]), lambda { "Parsing failed on #{config[:port].inspect} method :port, expected #{config[:port].inspect}, got #{domain.port.inspect}" }
5557
end
5658
end
5759
end

0 commit comments

Comments
 (0)