Compare commits

1 Commits

Author SHA1 Message Date
Mikan
71ffcc89bf fix 2026-02-13 21:58:35 +03:00
12 changed files with 256 additions and 223 deletions

1
.gitignore vendored
View File

@@ -1,5 +1,6 @@
# Environment # Environment
.env .env
domains.txt
# Certificates and secrets # Certificates and secrets
/nginx/certs/ /nginx/certs/

175
README.md
View File

@@ -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.

View File

@@ -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

View File

@@ -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

View File

@@ -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:

View File

@@ -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
View File

38
scripts/01-init-ca.sh Normal file
View 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
View File

0
scripts/add-service.sh Executable file → Normal file
View File

View 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
View 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