commit 10b772807df1ca9a30cf4f79e05b560bbd35df5f Author: Hardik Date: Wed Jun 3 23:45:19 2026 +0000 feat: initial homelab docker stack commit Sets up the complete self-hosted infrastructure on Voyager (HP t630 thin client): DNS Stack (dns/): - Pi-hole for network-wide ad blocking - Unbound as recursive DNS resolver - dnscrypt-proxy for DNS-over-HTTPS via Cloudflare/Quad9 Services: - Vaultwarden - self-hosted password manager (Bitwarden compatible) - Forgejo - self-hosted git mirror (primary on PMS1, mirror here) - Karakeep - self-hosted bookmark manager - Resilio Sync - P2P sync for PMS1 database backups Tunneling: - Newt - Pangolin tunnel client for exposing services via tunnel.pelagiamarine.com without open ports All services exposed externally via Pangolin reverse proxy on PMS1. Local DNS resolves through Pi-hole → Unbound → dnscrypt-proxy chain. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bea60da --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +# Forgejo data +forgejo/data/ + +# Vaultwarden data +vaultwarden/vw-data/ + +# Pi-hole data +dns/etc-pihole/ + +# Resilio data and config (contains keys/identity) +resilio/config/ +resilio/sync/ + +# Karakeep data +karakeep/data/ + +# dnscrypt cache +dns/dnscrypt/cache/ diff --git a/dns/compose.yaml b/dns/compose.yaml new file mode 100644 index 0000000..0134249 --- /dev/null +++ b/dns/compose.yaml @@ -0,0 +1,57 @@ +networks: + dns_net: + driver: bridge + ipam: + config: + - subnet: 172.20.0.0/24 + +services: + + dnscrypt-proxy: + image: klutchell/dnscrypt-proxy:latest + container_name: dnscrypt-proxy + restart: unless-stopped + networks: + dns_net: + ipv4_address: 172.20.0.3 + volumes: + - ./dnscrypt/dnscrypt-proxy.toml:/config/dnscrypt-proxy.toml:ro + - ./dnscrypt/cache:/config + healthcheck: + test: ["CMD", "wget", "-q", "--spider", "http://localhost:8053"] + interval: 10s + timeout: 5s + retries: 5 + + unbound: + build: ./unbound + container_name: unbound + restart: unless-stopped + networks: + dns_net: + ipv4_address: 172.20.0.2 + volumes: + - ./unbound/unbound.conf:/etc/unbound/unbound.conf:ro + - ./unbound/root.hints:/etc/unbound/root.hints:ro + + pihole: + image: pihole/pihole:latest + container_name: pihole + restart: unless-stopped + networks: + dns_net: + ipv4_address: 172.20.0.4 + ports: + - "53:53/tcp" + - "53:53/udp" + - "80:80/tcp" + - "443:443/tcp" + environment: + TZ: 'Asia/Kolkata' + FTLCONF_webserver_api_password: 'changeme' + FTLCONF_dns_listeningMode: 'all' + FTLCONF_dns_upstreams: '172.20.0.2#5335' + volumes: + - ./etc-pihole:/etc/pihole + cap_add: + - NET_ADMIN diff --git a/dns/dnscrypt/dnscrypt-proxy.toml b/dns/dnscrypt/dnscrypt-proxy.toml new file mode 100644 index 0000000..7758656 --- /dev/null +++ b/dns/dnscrypt/dnscrypt-proxy.toml @@ -0,0 +1,14 @@ +# Listen on all interfaces inside the container +listen_addresses = ['0.0.0.0:5053'] + +# Use these DoH servers (both no-logs, DNSSEC) +server_names = ['cloudflare', 'quad9-doh-ip4-port443-filter-ecs-pri'] + +[sources.public-resolvers] + urls = ['https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v3/public-resolvers.md', + 'https://download.dnscrypt.info/resolvers-list/v3/public-resolvers.md'] + cache_file = '/config/public-resolvers.md' + minisign_key = 'RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3' + +[anonymized_dns] + skip_incompatible = true diff --git a/dns/unbound/Dockerfile b/dns/unbound/Dockerfile new file mode 100644 index 0000000..6fde7d0 --- /dev/null +++ b/dns/unbound/Dockerfile @@ -0,0 +1,3 @@ +FROM alpine:latest +RUN apk add --no-cache unbound +ENTRYPOINT ["unbound", "-d", "-c", "/etc/unbound/unbound.conf"] diff --git a/dns/unbound/root.hints b/dns/unbound/root.hints new file mode 100644 index 0000000..0a04ecf --- /dev/null +++ b/dns/unbound/root.hints @@ -0,0 +1,92 @@ +; This file holds the information on root name servers needed to +; initialize cache of Internet domain name servers +; (e.g. reference this file in the "cache . " +; configuration file of BIND domain name servers). +; +; This file is made available by InterNIC +; under anonymous FTP as +; file /domain/named.cache +; on server FTP.INTERNIC.NET +; -OR- RS.INTERNIC.NET +; +; last update: May 21, 2026 +; related version of root zone: 2026052101 +; +; FORMERLY NS.INTERNIC.NET +; +. 3600000 NS A.ROOT-SERVERS.NET. +A.ROOT-SERVERS.NET. 3600000 A 198.41.0.4 +A.ROOT-SERVERS.NET. 3600000 AAAA 2001:503:ba3e::2:30 +; +; FORMERLY NS1.ISI.EDU +; +. 3600000 NS B.ROOT-SERVERS.NET. +B.ROOT-SERVERS.NET. 3600000 A 170.247.170.2 +B.ROOT-SERVERS.NET. 3600000 AAAA 2801:1b8:10::b +; +; FORMERLY C.PSI.NET +; +. 3600000 NS C.ROOT-SERVERS.NET. +C.ROOT-SERVERS.NET. 3600000 A 192.33.4.12 +C.ROOT-SERVERS.NET. 3600000 AAAA 2001:500:2::c +; +; FORMERLY TERP.UMD.EDU +; +. 3600000 NS D.ROOT-SERVERS.NET. +D.ROOT-SERVERS.NET. 3600000 A 199.7.91.13 +D.ROOT-SERVERS.NET. 3600000 AAAA 2001:500:2d::d +; +; FORMERLY NS.NASA.GOV +; +. 3600000 NS E.ROOT-SERVERS.NET. +E.ROOT-SERVERS.NET. 3600000 A 192.203.230.10 +E.ROOT-SERVERS.NET. 3600000 AAAA 2001:500:a8::e +; +; FORMERLY NS.ISC.ORG +; +. 3600000 NS F.ROOT-SERVERS.NET. +F.ROOT-SERVERS.NET. 3600000 A 192.5.5.241 +F.ROOT-SERVERS.NET. 3600000 AAAA 2001:500:2f::f +; +; FORMERLY NS.NIC.DDN.MIL +; +. 3600000 NS G.ROOT-SERVERS.NET. +G.ROOT-SERVERS.NET. 3600000 A 192.112.36.4 +G.ROOT-SERVERS.NET. 3600000 AAAA 2001:500:12::d0d +; +; FORMERLY AOS.ARL.ARMY.MIL +; +. 3600000 NS H.ROOT-SERVERS.NET. +H.ROOT-SERVERS.NET. 3600000 A 198.97.190.53 +H.ROOT-SERVERS.NET. 3600000 AAAA 2001:500:1::53 +; +; FORMERLY NIC.NORDU.NET +; +. 3600000 NS I.ROOT-SERVERS.NET. +I.ROOT-SERVERS.NET. 3600000 A 192.36.148.17 +I.ROOT-SERVERS.NET. 3600000 AAAA 2001:7fe::53 +; +; OPERATED BY VERISIGN, INC. +; +. 3600000 NS J.ROOT-SERVERS.NET. +J.ROOT-SERVERS.NET. 3600000 A 192.58.128.30 +J.ROOT-SERVERS.NET. 3600000 AAAA 2001:503:c27::2:30 +; +; OPERATED BY RIPE NCC +; +. 3600000 NS K.ROOT-SERVERS.NET. +K.ROOT-SERVERS.NET. 3600000 A 193.0.14.129 +K.ROOT-SERVERS.NET. 3600000 AAAA 2001:7fd::1 +; +; OPERATED BY ICANN +; +. 3600000 NS L.ROOT-SERVERS.NET. +L.ROOT-SERVERS.NET. 3600000 A 199.7.83.42 +L.ROOT-SERVERS.NET. 3600000 AAAA 2001:500:9f::42 +; +; OPERATED BY WIDE +; +. 3600000 NS M.ROOT-SERVERS.NET. +M.ROOT-SERVERS.NET. 3600000 A 202.12.27.33 +M.ROOT-SERVERS.NET. 3600000 AAAA 2001:dc3::35 +; End of file \ No newline at end of file diff --git a/dns/unbound/unbound.conf b/dns/unbound/unbound.conf new file mode 100644 index 0000000..e2a4c0f --- /dev/null +++ b/dns/unbound/unbound.conf @@ -0,0 +1,22 @@ +server: + verbosity: 1 + interface: 0.0.0.0 + port: 5335 + do-ip4: yes + do-udp: yes + do-tcp: yes + do-ip6: no + access-control: 0.0.0.0/0 allow + root-hints: "/etc/unbound/root.hints" + harden-glue: yes + harden-dnssec-stripped: yes + use-caps-for-id: yes + edns-buffer-size: 1472 + prefetch: yes + num-threads: 1 + hide-identity: yes + hide-version: yes + +forward-zone: + name: "." + forward-addr: 172.20.0.3@5053 diff --git a/dns/unbound/unbound1.conf b/dns/unbound/unbound1.conf new file mode 100644 index 0000000..bac9c71 --- /dev/null +++ b/dns/unbound/unbound1.conf @@ -0,0 +1 @@ + diff --git a/forgejo/compose.yml b/forgejo/compose.yml new file mode 100644 index 0000000..0276973 --- /dev/null +++ b/forgejo/compose.yml @@ -0,0 +1,14 @@ +services: + forgejo: + image: codeberg.org/forgejo/forgejo:10 + container_name: forgejo + restart: unless-stopped + environment: + - USER_UID=1000 + - USER_GID=1000 + - FORGEJO__database__DB_TYPE=sqlite3 + volumes: + - ./data:/data + ports: + - 3000:3000 + - 22222:22 # SSH for git push/pull diff --git a/karakeep/.env b/karakeep/.env new file mode 100644 index 0000000..11367d5 --- /dev/null +++ b/karakeep/.env @@ -0,0 +1,4 @@ +KARAKEEP_VERSION=release +NEXTAUTH_SECRET=myNVIxjmYr46m3ZPSzC2//PSfAvYtANvuxGFGBcnwbvQGlNx +MEILI_MASTER_KEY=KYq5jf6aygLGUW8PAVVGcDzH+/bvlGgMsT8BSTmqUhafwecL +NEXTAUTH_URL=https://bookmarks.tunnel.pelagiamarine.com diff --git a/karakeep/docker-compose.yml b/karakeep/docker-compose.yml new file mode 100644 index 0000000..fcf373e --- /dev/null +++ b/karakeep/docker-compose.yml @@ -0,0 +1,44 @@ +services: + web: + image: ghcr.io/karakeep-app/karakeep:${KARAKEEP_VERSION:-release} + restart: unless-stopped + volumes: + # By default, the data is stored in a docker volume called "data". + # If you want to mount a custom directory, change the volume mapping to: + # - /path/to/your/directory:/data + - data:/data + ports: + - 3333:3000 + env_file: + - .env + environment: + MEILI_ADDR: http://meilisearch:7700 + BROWSER_WEB_URL: http://chrome:9222 + OPENAI_API_KEY: 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 + + # You almost never want to change the value of the DATA_DIR variable. + # If you want to mount a custom directory, change the volume mapping above instead. + DATA_DIR: /data # DON'T CHANGE THIS + chrome: + image: gcr.io/zenika-hub/alpine-chrome:124 + restart: unless-stopped + command: + - --no-sandbox + - --disable-gpu + - --disable-dev-shm-usage + - --remote-debugging-address=0.0.0.0 + - --remote-debugging-port=9222 + - --hide-scrollbars + meilisearch: + image: getmeili/meilisearch:v1.41.0 + restart: unless-stopped + env_file: + - .env + environment: + MEILI_NO_ANALYTICS: "true" + volumes: + - meilisearch:/meili_data + +volumes: + meilisearch: + data: diff --git a/newt/docker-compose.yml b/newt/docker-compose.yml new file mode 100644 index 0000000..ba26cc3 --- /dev/null +++ b/newt/docker-compose.yml @@ -0,0 +1,9 @@ +services: + newt: + image: fosrl/newt + container_name: newt + restart: unless-stopped + environment: + - PANGOLIN_ENDPOINT=https://pangolin.pelagiamarine.com + - NEWT_ID=0rq10j85e7hbh4g + - NEWT_SECRET=orv1rdmsm0ykkoee5ayyzmpxvxq2vss5w5qjf2pkx6rb6ddl diff --git a/resilio/compose.yml b/resilio/compose.yml new file mode 100644 index 0000000..4d4fbec --- /dev/null +++ b/resilio/compose.yml @@ -0,0 +1,16 @@ +services: + resilio: + image: lscr.io/linuxserver/resilio-sync:latest + container_name: resilio + restart: unless-stopped + environment: + - PUID=1000 + - PGID=1000 + - TZ=Asia/Kolkata + volumes: + - ./config:/config + - /home/shad0w/backups:/sync/backups + + ports: + - 8888:8888 + - 55555:55555 diff --git a/vaultwarden/compose.yml b/vaultwarden/compose.yml new file mode 100644 index 0000000..e62aafe --- /dev/null +++ b/vaultwarden/compose.yml @@ -0,0 +1,11 @@ +services: + vaultwarden: + image: vaultwarden/server:latest + container_name: vaultwarden + restart: unless-stopped + environment: + DOMAIN: "https://vaultwarden.tunnel.pelagiamarine.com" + volumes: + - ./vw-data/:/data/ + ports: + - 8000:80