local compose = import 'compose.libsonnet'; local Compose = compose.Compose; local Command = compose.Command; local Port = compose.Port; local MediaService = compose.MediaService; local MediaMounts = compose.MediaMounts; local HomelabDomain = compose.HomelabDomain; function(secrets={}) Compose({ gluetun: { image: 'qmcgaw/gluetun', cap_add: ['NET_ADMIN'], devices: ['/dev/net/tun:/dev/net/tun'], environment: { TZ: 'America/New_York', // VPN_SERVICE_PROVIDER: 'custom', // VPN_TYPE: 'wireguard', // VPN_PORT_FORWARDING_PROVIDER: 'protonvpn', // VPN_ENDPOINT_IP: std.get(secrets, 'VPN_ENDPOINT_IP'), // VPN_ENDPOINT_PORT: std.get(secrets, 'VPN_ENDPOINT_PORT'), // WIREGUARD_PUBLIC_KEY: std.get(secrets, 'WIREGUARD_PUBLIC_KEY'), // WIREGUARD_PRIVATE_KEY: std.get(secrets, 'WIREGUARD_PRIVATE_KEY'), // WIREGUARD_ADDRESSES: std.get(secrets, 'WIREGUARD_ADDRESSES'), VPN_SERVICE_PROVIDER: 'protonvpn', VPN_PORT_FORWARDING: 'on', OPENVPN_USER: std.get(secrets, 'OPENVPN_USER'), OPENVPN_PASSWORD: std.get(secrets, 'OPENVPN_PASSWORD'), SERVER_HOSTNAMES: 'node-ch-08.protonvpn.net', }, ports: [ // http proxy // Port(8888), // shadowsocks proxy // Port(8388), // Port(8388, kind='udp'), // app local ports // deluge // Port(58846), // Port(58846, kind='udp'), // transmission Port(9091), Port(9091, kind='udp'), ], webPort:: 8000, volumes: { gluetun_data: '/gluetun' }, }, traefik: { image: 'traefik:latest', command: Command({ 'log.level': 'DEBUG', 'api.insecure': 'true', 'providers.docker': 'true', 'providers.docker.exposedbydefault': 'false', 'entrypoints.web.address': ':80', 'entrypoints.web-tls.address': ':443', 'entrypoints.web-tls.http.tls.domains[0].main': HomelabDomain, 'entrypoints.web-tls.http.tls.domains[0].sans': '*.%s' % HomelabDomain, 'entrypoints.web-tls.http.tls.certresolver': 'letsencrypt', 'certificatesresolvers.letsencrypt.acme.dnschallenge': true, 'certificatesresolvers.letsencrypt.acme.dnschallenge.provider': 'luadns', 'certificatesresolvers.letsencrypt.acme.email': 'mat@mat.services', 'certificatesresolvers.letsencrypt.acme.storage': '/letsencrypt/acme.json', }), docker:: true, webPort:: 8080, ports: [ Port(80), Port(443), ], environment: { LUADNS_API_USERNAME: 'mat@mat.services', LUADNS_API_TOKEN: std.get(secrets, 'LETSENCRYPT_DNS_PROVIDER_KEY'), }, traefik:: { // 'traefik.http.routers.http-catchall.rule': 'hostregexp(`{host:.+}`)' // 'traefik.http.routers.http-catchall.entrypoints': 'web' // 'traefik.http.routers.http-catchall.middlewares': 'redirect-to-https' // 'traefik.http.middlewares.redirect-to-https.redirectscheme.scheme': 'https' }, volumes: { letsencrypt_data: '/letsencrypt' } }, portainer: { image: 'portainer/portainer-ce:latest', docker:: true, volumes: { portainer_portainer_data: '/data' }, webPort:: 9000, // useful when traefik is having issues // ports: [Port(9443)], }, transmission: MediaService( name='transmission', env={ USER: 'mat', PASS: std.get(secrets, 'TRANSMISSION_PASS'), // PEERPORT: 55249, }, mounts={ torrents: '/downloads' }, webPort=9091, extras={ gluetun:: true }, ), // deluge: MediaService( // name='deluge', // env={ DELUGE_LOGLEVEL: 'error' }, // mounts={ torrents: '/downloads' }, // webPort=8112, // extras={ gluetun:: true }, // external=true, // ), prowlarr: MediaService( name='prowlarr', tag='develop', webPort=9696, mounts={ torrents: '/downloads', 'passport-5tb': '/passport-5tb', 'passport-1tb': '/passport-1tb', }, extras={ gluetun:: true }, external=true, ), bazarr: MediaService( name='bazarr', webPort=6767, mounts={ 'passport-5tb': '/passport-5tb', 'passport-1tb': '/passport-1tb', }, extras={ gluetun:: true }, external=true, ), radarr: MediaService( name='radarr', webPort=7878, mounts={ 'passport-5tb/movies': '/passport-5tb', 'passport-1tb/movies': '/passport-1tb', torrents: '/downloads', }, extras={ gluetun:: true }, external=true, ), sonarr: MediaService( name='sonarr', webPort=8989, mounts={ 'passport-5tb/tv': '/passport-5tb', 'passport-1tb/tv': '/passport-1tb', torrents: '/downloads', }, extras={ gluetun:: true }, external=true, ), plex: { image: 'plexinc/pms-docker', environment: { TZ: 'America/New_York', PLEX_CLAIM: std.get(secrets, 'PLEX_CLAIM'), // ADVERTISE_IP: std.get(secrets, 'PLEX_ADVERTISE_IP'), }, volumes: { media_plex_config: '/config' }, mounts:: MediaMounts({ 'torrents/plex-transcode': '/transcode', 'passport-5tb': '/passport-5tb', 'passport-1tb': '/passport-1tb', }), devices: ['/dev/dri:/dev/dri'], webPort:: 32400, ports: [ // plex Port(32400), // companion Port(3005), // dlna Port(32469), Port(1900, kind='udp'), // gdm network discovery Port(32410, kind='udp'), Port(32412, kind='udp'), Port(32413, kind='udp'), Port(32414, kind='udp'), // bonjour/avahi // Port(5353, kind='udp'), // plex for roku via companion // Port(8324), ], }, archivebox: { image: 'archivebox/archivebox:dev', command: 'server --quick-init 0.0.0.0:8000', // TODO: hack to workaround https://github.com/ArchiveBox/ArchiveBox/issues/1002 // entrypoint: '/bin/bash', // command: '-c "chown -R archivebox:archivebox /app/archivebox/core/migrations && /app/bin/docker_entrypoint.sh server --quick-init 0.0.0.0:8000"', environment: { ALLOWED_HOSTS: '*', MEDIA_MAX_SIZE: '750m', RESOLUTION: '1024,768', }, mounts:: MediaMounts({ 'passport-5tb/archivebox': '/data' }), webPort:: 8000, host:: 'archive', }, actual: { image: 'actualbudget/actual-server:latest', environment: { userFilesPath: '/data/user', serverFilesPath: '/data/server', externalPort: 5006, }, volumes: { actual_data: '/data' }, webPort:: 5006, }, })