Add nginx-proxy-acme

This commit is contained in:
2026-01-25 14:39:16 +00:00
parent 57590e63b1
commit d84e412532
3 changed files with 192 additions and 0 deletions
+142
View File
@@ -0,0 +1,142 @@
# nginx-proxy + acme-companion
Automated reverse proxy with Let's Encrypt SSL certificates.
## Setup
1. Create the data directories:
```bash
sudo mkdir -p /srv/nginx-proxy-acme/{certs,vhost.d,html,conf.d,acme}
```
2. Copy configuration files:
```bash
sudo cp conf/conf.d/* /srv/nginx-proxy-acme/conf.d/
sudo cp conf/vhost.d/* /srv/nginx-proxy-acme/vhost.d/
```
3. Configure environment:
```bash
cp .env.example .env
# Edit .env with your email
```
4. Start the proxy:
```bash
docker compose up -d
```
## Architecture
- **nginx-proxy**: Reverse proxy with auto-discovery of Docker containers
- **acme-companion**: Automatic Let's Encrypt certificate management
- **static-certs**: Dummy container that triggers cert issuance for non-container backends
## Security
All hosts receive these security features via `vhost.d/default`:
- **HSTS**: Strict-Transport-Security header (1 year)
- **Security headers**: X-Content-Type-Options, X-Frame-Options, X-XSS-Protection, Referrer-Policy
- **Block exploits**: WAF rules against SQL injection, XSS, file injection, spam, bad user agents
## Access Control
### Private Hosts (IP restricted)
Private hosts include `vhost.d/private` which restricts access to:
- 192.168.1.0/24 (local network)
- 172.16.0.0/12 (Docker networks)
To make a new host private, create a vhost.d file:
```bash
echo 'include /etc/nginx/vhost.d/private;' | sudo tee /srv/nginx-proxy-acme/vhost.d/myapp.kolpacksoftware.com
```
### Public Hosts
Public hosts have no vhost.d file (only `default` applies). They get security headers and block-exploits but no IP restrictions.
Current public hosts:
- chd.kolpacksoftware.com
- linkding.kolpacksoftware.com
- organizer.rmstsa.org
- ridge-resources.org
- rmstsa.org / www.rmstsa.org
- share.kolpacksoftware.com
- vikunja.kolpacksoftware.com
## Adding a Proxied Service
Add these environment variables to any container:
```yaml
services:
myapp:
image: myapp:latest
environment:
- VIRTUAL_HOST=myapp.kolpacksoftware.com
- VIRTUAL_PORT=8080
- LETSENCRYPT_HOST=myapp.kolpacksoftware.com
networks:
- npm-network
networks:
npm-network:
external: true
```
Then if private, add the vhost.d file as shown above.
## Static IP Backends
Services running on physical hosts or VMs (not Docker) are configured in `conf.d/static-upstreams.conf`:
| Domain | Backend |
|--------|---------|
| portainer.kolpacksoftware.com | 172.17.0.1:9443 |
| btt-cb1.kolpacksoftware.com | 192.168.1.173:80 |
| hats.kolpacksoftware.com | 192.168.1.66:9999 |
| pve-nas.kolpacksoftware.com | 192.168.1.245:8006 |
| unraid.kolpacksoftware.com | 192.168.1.192:80 |
All static backends are private (IP restricted).
To add a new static backend:
1. Add server block to `conf.d/static-upstreams.conf`
2. Add domain to `static-certs` container's VIRTUAL_HOST and LETSENCRYPT_HOST in docker-compose.yaml
3. Reload: `docker exec nginx-proxy nginx -s reload`
## Directory Structure
```
/srv/nginx-proxy-acme/
├── acme/ # acme.sh state (auto-managed)
├── certs/ # SSL certificates (auto-managed)
├── conf.d/
│ ├── block-exploits.conf # WAF rules
│ └── static-upstreams.conf # Static IP backend server blocks
├── html/ # ACME challenge files (auto-managed)
└── vhost.d/
├── default # Security headers + HSTS + block-exploits (all hosts)
├── private # IP allowlist (private hosts include this)
├── docker-registry.* # Special config (auth headers + private)
└── <hostname> # Per-host includes (usually just 'include private')
```
## Reload Config
After changing vhost.d or conf.d files:
```bash
docker exec nginx-proxy nginx -s reload
```
## Multiple Domains
For multiple domains on one cert:
```yaml
environment:
- VIRTUAL_HOST=example.com,www.example.com
- LETSENCRYPT_HOST=example.com,www.example.com
```
Create vhost.d entries for each domain if private.