Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
71ffcc89bf |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,5 +1,6 @@
|
|||||||
# Environment
|
# Environment
|
||||||
.env
|
.env
|
||||||
|
domains.txt
|
||||||
|
|
||||||
# Certificates and secrets
|
# Certificates and secrets
|
||||||
/nginx/certs/
|
/nginx/certs/
|
||||||
|
|||||||
175
README.md
175
README.md
@@ -1,130 +1,117 @@
|
|||||||
# Local DNS Services with Docker
|
# Локальная сеть с доменами `.mikan` и HTTPS
|
||||||
|
|
||||||
This project provides a local development infrastructure with automatic DNS resolution for custom domains (e.g., `.mikan` or `.local`) and valid HTTPS certificates.
|
Система для запуска сервисов в Docker с автоматическим HTTPS, локальными доменами (`service.mikan`, `service.local`) и возможностью расширения (Tailscale, публичные домены).
|
||||||
|
|
||||||
## Features
|
## Требования
|
||||||
|
|
||||||
- Automatic DNS resolution for `*.yourdomain` and `*.yourdomain.local`
|
- Docker + Docker Compose
|
||||||
- Valid HTTPS certificates for local domains using `mkcert`
|
- `mkcert` — [инструкция по установке](https://github.com/FiloSottile/mkcert#installation)
|
||||||
- Easy service deployment with `VIRTUAL_HOST` environment variables
|
- `bash`, `coreutils`
|
||||||
- Ready for future expansion: public domains, Let's Encrypt, Tailscale
|
|
||||||
- Single-command service creation
|
|
||||||
|
|
||||||
## Requirements
|
## Быстрый старт
|
||||||
|
|
||||||
- Docker and Docker Compose
|
1. **Клонируй репозиторий**
|
||||||
- `mkcert` installed on the host system
|
|
||||||
|
|
||||||
## Quick Start
|
|
||||||
|
|
||||||
1. Clone this repository and enter the directory:
|
|
||||||
```bash
|
```bash
|
||||||
git clone <repository-url> local-dns
|
git clone ... && cd local-dns
|
||||||
cd local-dns
|
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Initialize the project:
|
2. **Настрой домен (опционально)**
|
||||||
```bash
|
```bash
|
||||||
./scripts/00-init.sh
|
echo "LOCAL_DOMAIN=mikan" > .env
|
||||||
```
|
```
|
||||||
This creates a `.env` file from `.env.example` and sets up the directory structure.
|
Замени `mikan` на желаемый суффикс (например, `home`).
|
||||||
|
|
||||||
3. Generate TLS certificates:
|
3. **Инициализируй CA и базовый сертификат**
|
||||||
```bash
|
```bash
|
||||||
./scripts/01-generate-cert.sh
|
./scripts/01-init-ca.sh
|
||||||
```
|
```
|
||||||
This creates trusted certificates for your local domain.
|
- Создаст доверенный корневой сертификат (`ca/rootCA.pem`)
|
||||||
|
- Сгенерирует `default.crt` для nginx-proxy
|
||||||
|
|
||||||
4. Start the core infrastructure:
|
4. **Установи корневой сертификат в систему**
|
||||||
|
Импортируй файл `ca/rootCA.pem` в хранилище **доверенных корневых центров сертификации**:
|
||||||
|
- **Linux**:
|
||||||
|
```bash
|
||||||
|
sudo cp ca/rootCA.pem /usr/local/share/ca-certificates/mkcert-local.crt
|
||||||
|
sudo update-ca-certificates
|
||||||
|
```
|
||||||
|
- **Windows/macOS**: двойной клик по файлу → «Доверять всегда» (macOS) или импорт в «Доверенные корневые центры» (Windows)
|
||||||
|
|
||||||
|
5. **Запусти инфраструктуру**
|
||||||
```bash
|
```bash
|
||||||
docker compose up -d
|
docker compose up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
5. Add your first service (example: Gitea on port 3000):
|
6. **Добавь сервис**
|
||||||
```bash
|
```bash
|
||||||
./scripts/add-service.sh gitea 3000
|
./scripts/add-service.sh gitea
|
||||||
```
|
```
|
||||||
Then edit `services/gitea/docker-compose.yml` to set the correct image and volumes.
|
Сервис будет доступен по:
|
||||||
|
- `https://gitea.mikan`
|
||||||
|
- `https://gitea.local`
|
||||||
|
|
||||||
|
\+ может пригодиться:
|
||||||
|
|
||||||
6. Start the new service:
|
|
||||||
```bash
|
```bash
|
||||||
docker compose -f docker-compose.yml -f services/gitea/docker-compose.yml up -d
|
Add-Content -Path "C:\Windows\System32\drivers\etc\hosts" -Value "10.0.0.3 youtrack.mikan"
|
||||||
```
|
```
|
||||||
|
|
||||||
7. Visit `https://gitea.yourdomain` in your browser (replace `yourdomain` with your configured domain).
|
7. **Настрой сервис в Docker Compose**
|
||||||
|
Убедись, что в `docker-compose.yml` сервиса указано:
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
gitea:
|
||||||
|
environment:
|
||||||
|
- VIRTUAL_HOST=gitea.mikan,gitea.local
|
||||||
|
- VIRTUAL_PORT=3000 # порт внутри контейнера
|
||||||
|
networks:
|
||||||
|
- devnet
|
||||||
|
dns: 10.0.0.2 # обязательно для резолвинга доменов из контейнеров
|
||||||
|
```
|
||||||
|
|
||||||
## Configuration
|
## Важные замечания
|
||||||
|
|
||||||
Edit the `.env` file to customize your setup:
|
### DNS из контейнеров
|
||||||
|
Контейнеры **не могут** резолвить `*.mikan` без явного указания DNS:
|
||||||
|
```yaml
|
||||||
|
dns: 10.0.0.2 # IP dnsmasq
|
||||||
|
```
|
||||||
|
Добавляй эту строку во все сервисы, которым нужен доступ к другим по домену.
|
||||||
|
|
||||||
- `LOCAL_DOMAIN`: Your local domain suffix (default: `mikan`)
|
### Обновление сертификатов
|
||||||
- `PUBLIC_DOMAIN`: Optional public domain for Let's Encrypt certificates
|
При добавлении сервиса через `add-service.sh`:
|
||||||
- `LETSENCRYPT_EMAIL`: Email for Let's Encrypt notifications
|
- Автоматически обновляется `domains.txt`
|
||||||
- Network settings (`NGINX_IP`, `DNSMASQ_IP`, etc.)
|
- Генерируется новый `default.crt`
|
||||||
|
- Перезагружается `nginx-proxy`
|
||||||
|
|
||||||
After changing `.env`, re-run the initialization and certificate scripts.
|
### Пути
|
||||||
|
- Сертификаты: `nginx/certs/default.crt`
|
||||||
|
- Домены: `domains.txt`
|
||||||
|
- Корневой CA: `ca/rootCA.pem`
|
||||||
|
|
||||||
## DNS Setup
|
## Расширение
|
||||||
|
|
||||||
### Linux/macOS
|
### Tailscale
|
||||||
|
Добавь в `docker-compose.yml` сервис `tailscale` и объявляй дополнительные домены:
|
||||||
Use the included `dnsmasq` service for automatic DNS resolution:
|
```yaml
|
||||||
|
environment:
|
||||||
```bash
|
- VIRTUAL_HOST=gitea.mikan,gitea.local,gitea.yourname.ts.net
|
||||||
docker compose -f docker-compose.yml -f docker-compose.dnsmasq.yml up -d
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Then configure your system to use `10.0.0.2` as the primary DNS server.
|
### Публичный домен
|
||||||
|
1. Купи домен (например, `example.com`)
|
||||||
### Windows (WSL2)
|
2. В `.env` добавь:
|
||||||
|
```env
|
||||||
Windows reserves port 53, so `dnsmasq` cannot run on the host. Instead:
|
PUBLIC_DOMAIN=example.com
|
||||||
|
|
||||||
1. Work inside WSL2
|
|
||||||
2. Manually add entries to the Windows hosts file:
|
|
||||||
```powershell
|
|
||||||
# Run PowerShell as Administrator
|
|
||||||
Add-Content -Path "C:\Windows\System32\drivers\etc\hosts" -Value "127.0.0.1 gitea.mikan"
|
|
||||||
Add-Content -Path "C:\Windows\System32\drivers\etc\hosts" -Value "127.0.0.1 gitea.mikan.local"
|
|
||||||
```
|
```
|
||||||
|
3. В сервисах укажи:
|
||||||
## Certificate Trust
|
```yaml
|
||||||
|
environment:
|
||||||
After running `./scripts/01-generate-cert.sh`, install the root certificate on your devices:
|
- VIRTUAL_HOST=gitea.mikan,gitea.local,gitea.example.com
|
||||||
|
- LETSENCRYPT_HOST=gitea.example.com
|
||||||
- **Linux**: Depends on distribution (usually via `update-ca-certificates`)
|
|
||||||
- **macOS**:
|
|
||||||
```bash
|
|
||||||
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain ca/rootCA.pem
|
|
||||||
```
|
```
|
||||||
- **Windows**:
|
Сертификат для `example.com` получит `acme-companion`.
|
||||||
1. Copy `ca/rootCA.pem` to Windows
|
|
||||||
2. Open `certmgr.msc`
|
|
||||||
3. Import into "Trusted Root Certification Authorities"
|
|
||||||
|
|
||||||
## Adding Public Domain Support
|
---
|
||||||
|
|
||||||
To enable Let's Encrypt certificates for a public domain:
|
Готово. Теперь все сервисы работают по HTTPS с валидными сертификатами.
|
||||||
|
|
||||||
1. Set in `.env`:
|
|
||||||
```ini
|
|
||||||
PUBLIC_DOMAIN=yourdomain.com
|
|
||||||
LETSENCRYPT_EMAIL=you@yourdomain.com
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Re-run initialization:
|
|
||||||
```bash
|
|
||||||
./scripts/00-init.sh
|
|
||||||
./scripts/01-generate-cert.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
3. New services will automatically request Let's Encrypt certificates for the public domain.
|
|
||||||
|
|
||||||
## Service Management
|
|
||||||
|
|
||||||
- **Add a service**: `./scripts/add-service.sh <name> <port>`
|
|
||||||
- **Start all**: `docker compose up -d`
|
|
||||||
- **Start with dnsmasq**: `docker compose -f docker-compose.yml -f docker-compose.dnsmasq.yml up -d`
|
|
||||||
- **Stop all**: `docker compose down`
|
|
||||||
|
|
||||||
All service data is stored in the `services/` directory and persists between restarts.
|
|
||||||
@@ -1,9 +1,2 @@
|
|||||||
address=/.mikan/10.0.0.3
|
# Этот файл будет перезаписан при запуске ./scripts/02-apply-config.sh
|
||||||
address=/.mikan.local/10.0.0.3
|
# Не редактируйте вручную
|
||||||
local=/.mikan/
|
|
||||||
local=/.mikan.local/
|
|
||||||
no-resolv
|
|
||||||
server=1.1.1.1
|
|
||||||
server=8.8.8.8
|
|
||||||
log-queries
|
|
||||||
log-facility=/dev/stdout
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
version: '3.8'
|
|
||||||
|
|
||||||
services:
|
|
||||||
dnsmasq:
|
|
||||||
image: jpillora/dnsmasq
|
|
||||||
container_name: dnsmasq
|
|
||||||
restart: unless-stopped
|
|
||||||
ports:
|
|
||||||
- "53:53/udp"
|
|
||||||
- "53:53/tcp"
|
|
||||||
volumes:
|
|
||||||
- ./dnsmasq/dnsmasq.conf:/etc/dnsmasq.conf:ro
|
|
||||||
cap_add:
|
|
||||||
- NET_ADMIN
|
|
||||||
networks:
|
|
||||||
devnet:
|
|
||||||
ipv4_address: ${DNSMASQ_IP}
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "nslookup", "localhost", "127.0.0.1"]
|
|
||||||
interval: 30s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 3
|
|
||||||
|
|
||||||
networks:
|
|
||||||
devnet:
|
|
||||||
external: true
|
|
||||||
@@ -13,7 +13,6 @@ services:
|
|||||||
- ./nginx/certs:/etc/nginx/certs:ro
|
- ./nginx/certs:/etc/nginx/certs:ro
|
||||||
- ./nginx/vhost.d:/etc/nginx/vhost.d:ro
|
- ./nginx/vhost.d:/etc/nginx/vhost.d:ro
|
||||||
- ./nginx/html:/usr/share/nginx/html:rw
|
- ./nginx/html:/usr/share/nginx/html:rw
|
||||||
- ./nginx/proxy.conf:/etc/nginx/conf.d/proxy.conf
|
|
||||||
networks:
|
networks:
|
||||||
devnet:
|
devnet:
|
||||||
ipv4_address: ${NGINX_IP}
|
ipv4_address: ${NGINX_IP}
|
||||||
@@ -35,7 +34,6 @@ services:
|
|||||||
- ./nginx/certs:/etc/nginx/certs:rw
|
- ./nginx/certs:/etc/nginx/certs:rw
|
||||||
- ./acme:/etc/acme.sh
|
- ./acme:/etc/acme.sh
|
||||||
- ./nginx/vhost.d:/etc/nginx/vhost.d:rw
|
- ./nginx/vhost.d:/etc/nginx/vhost.d:rw
|
||||||
- ./nginx/proxy.conf:/etc/nginx/conf.d/proxy.conf
|
|
||||||
networks:
|
networks:
|
||||||
- devnet
|
- devnet
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head><title>Добро пожаловать!</title></head>
|
<head><title>Placeholder</title></head>
|
||||||
<body>
|
<body>
|
||||||
<h1>Сервисы .mikan</h1>
|
<p>Run ./scripts/00-init.sh to generate content</p>
|
||||||
<p>Добавьте свои сервисы в папку <code>services/</code></p>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
0
scripts/00-init.sh
Executable file → Normal file
0
scripts/00-init.sh
Executable file → Normal file
38
scripts/01-init-ca.sh
Normal file
38
scripts/01-init-ca.sh
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
ROOT_DIR="$SCRIPT_DIR/.."
|
||||||
|
|
||||||
|
if [ -f "$ROOT_DIR/.env" ]; then
|
||||||
|
export $(grep -v '^#' "$ROOT_DIR/.env" | xargs)
|
||||||
|
fi
|
||||||
|
|
||||||
|
LOCAL_DOMAIN=${LOCAL_DOMAIN:-mikan}
|
||||||
|
CA_DIR="$ROOT_DIR/ca"
|
||||||
|
CERTS_DIR="$ROOT_DIR/nginx/certs"
|
||||||
|
DOMAINS_FILE="$ROOT_DIR/domains.txt"
|
||||||
|
|
||||||
|
mkdir -p "$CA_DIR" "$CERTS_DIR"
|
||||||
|
|
||||||
|
if [ ! -f "$DOMAINS_FILE" ]; then
|
||||||
|
touch "$DOMAINS_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f "$CA_DIR/rootCA.pem" ]; then
|
||||||
|
mkcert -install
|
||||||
|
cp "$(mkcert -CAROOT)/rootCA.pem" "$CA_DIR/rootCA.pem"
|
||||||
|
cp "$(mkcert -CAROOT)/rootCA-key.pem" "$CA_DIR/rootCA-key.pem"
|
||||||
|
|
||||||
|
cat > "$DOMAINS_FILE" <<EOF
|
||||||
|
$LOCAL_DOMAIN
|
||||||
|
welcome.$LOCAL_DOMAIN
|
||||||
|
localhost
|
||||||
|
127.0.0.1
|
||||||
|
::1
|
||||||
|
*.services.$LOCAL_DOMAIN
|
||||||
|
*.services.local
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec "$SCRIPT_DIR/regenerate-cert.sh"
|
||||||
0
scripts/02-apply-config.sh
Executable file → Normal file
0
scripts/02-apply-config.sh
Executable file → Normal file
0
scripts/add-service.sh
Executable file → Normal file
0
scripts/add-service.sh
Executable file → Normal file
32
scripts/regenerate-cert.sh
Normal file
32
scripts/regenerate-cert.sh
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
ROOT_DIR="$SCRIPT_DIR/.."
|
||||||
|
|
||||||
|
if [ -f "$ROOT_DIR/.env" ]; then
|
||||||
|
export $(grep -v '^#' "$ROOT_DIR/.env" | xargs)
|
||||||
|
fi
|
||||||
|
|
||||||
|
DOMAINS_FILE="$ROOT_DIR/domains.txt"
|
||||||
|
CERTS_DIR="$ROOT_DIR/nginx/certs"
|
||||||
|
|
||||||
|
if [ ! -f "$DOMAINS_FILE" ]; then
|
||||||
|
echo "Error: $DOMAINS_FILE not found" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mapfile -t DOMAINS < <(grep -v '^$' "$DOMAINS_FILE")
|
||||||
|
|
||||||
|
if [ ${#DOMAINS[@]} -eq 0 ]; then
|
||||||
|
echo "Error: no domains found in $DOMAINS_FILE" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkcert \
|
||||||
|
-cert-file "$CERTS_DIR/default.crt.new" \
|
||||||
|
-key-file "$CERTS_DIR/default.key.new" \
|
||||||
|
"${DOMAINS[@]}"
|
||||||
|
|
||||||
|
mv "$CERTS_DIR/default.crt.new" "$CERTS_DIR/default.crt"
|
||||||
|
mv "$CERTS_DIR/default.key.new" "$CERTS_DIR/default.key"
|
||||||
11
scripts/reload-nginx.sh
Normal file
11
scripts/reload-nginx.sh
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
ROOT_DIR="$SCRIPT_DIR/.."
|
||||||
|
|
||||||
|
CERTS_DIR="$ROOT_DIR/nginx/certs"
|
||||||
|
cp "$CERTS_DIR/default.crt" "$CERTS_DIR/default.key" "$CERTS_DIR/"
|
||||||
|
|
||||||
|
docker compose -f "$ROOT_DIR/docker-compose.yml" exec nginx-proxy nginx -s reload 2>/dev/null || \
|
||||||
|
docker compose -f "$ROOT_DIR/docker-compose.yml" restart nginx-proxy
|
||||||
Reference in New Issue
Block a user