krz/skunky-art
Alternative privacy frontend for DeviantArt.
clone: git clone https://gitbay.org/krz/skunky-art.git
sonarcloud-cleanup: compose.vpn_example.yml · raw
1# SkunkyArt + optional VPN egress, in a single stack.
2#
3# Why: DeviantArt's API (AWS CloudFront + WAF) blocks some egress IPs on the
4# /_puppy path, which makes every DA-backed page fail with
5# `invalid character '<' looking for beginning of value` (Go trying to
6# json.Unmarshal a CloudFront HTML 403 page). Routing SkunkyArt's outbound
7# through a non-blocked VPN exit fixes it without any code change: devianter's
8# HTTP client honors HTTPS_PROXY/HTTP_PROXY.
9#
10# The VPN sidecar (gluetun) is OPTIONAL — it only starts under the "vpn" profile.
11# With the profile off, SkunkyArt runs exactly as the stock compose.yaml (direct).
12#
13# The VPN provider is YOUR choice: gluetun supports AirVPN, Mullvad, ProtonVPN,
14# PIA, and many others. Set VPN_SERVICE_PROVIDER and supply that provider's
15# required settings. Provider list + required variables:
16# https://github.com/qdm12/gluetun-wiki
17#
18# ---------------------------------------------------------------------------
19# Setup:
20# 1. Copy this file to compose.yaml (or run with `-f compose.vpn_example.yml`).
21# 2. Create a .env next to it (and `echo ".env" >> .gitignore`):
22#
23# # toggle VPN: uncomment both to route SkunkyArt through the VPN
24# #COMPOSE_PROFILES=vpn
25# #SKUNKY_PROXY=http://gluetun:8888
26#
27# # pick your provider (see the gluetun wiki for the exact name/vars)
28# VPN_SERVICE_PROVIDER=airvpn
29# VPN_TYPE=wireguard
30#
31# # WireGuard credentials (from your provider's config generator)
32# VPN_PRIVATE_KEY=<[Interface] PrivateKey>
33# VPN_PRESHARED_KEY=<[Peer] PresharedKey> # optional; some providers omit it
34# VPN_ADDRESSES=<[Interface] Address, e.g. 10.128.x.x/32>
35# VPN_COUNTRIES=Netherlands
36# TZ=America/Chicago
37#
38# 3. VPN on: uncomment the two toggle lines, then `docker compose up -d`.
39# VPN off: leave them commented, then `docker compose up -d`.
40#
41# Verify an exit is not blocked BEFORE trusting it:
42# curl -x http://127.0.0.1:8888 -s -o /dev/null -w "%{http_code}\n" \
43# "https://www.deviantart.com/_puppy/dabrowse/networkbar/rfy/deviations?page=0"
44# 400 (JSON "csrf: missing") = clean exit. 403 (text/html) = blocked, rotate servers.
45# ---------------------------------------------------------------------------
46
47services:
48 skunkyart:
49 container_name: skunkyart
50 restart: unless-stopped
51 # Published multi-arch image; pin a release tag (e.g. :1.3.3) for
52 # reproducible upgrades. To build from this checkout instead, comment out
53 # `image:` and uncomment `build:`, then `docker compose up -d --build`.
54 image: ghcr.io/krazywarez/skunky-art:latest
55 #build: .
56 ports:
57 - "127.0.0.1:3003:3003"
58 security_opt:
59 - no-new-privileges:true
60 volumes:
61 - ./config.json:/config.json:ro
62 # The image runs as uid 10000, so the host cache dir must be writable by it:
63 # mkdir -p cache && sudo chown -R 10000:10000 cache
64 - ./cache:/cache
65 environment:
66 # Empty by default = direct. Set SKUNKY_PROXY in .env to route via the VPN.
67 - HTTPS_PROXY=${SKUNKY_PROXY:-}
68 - HTTP_PROXY=${SKUNKY_PROXY:-}
69 - NO_PROXY=localhost,127.0.0.1
70 depends_on:
71 gluetun:
72 condition: service_healthy
73 required: false # optional dep: skunky still starts if gluetun is off
74 # (needs Docker Compose v2.20+; drop this block on older)
75
76 # --- optional VPN egress: only starts with the "vpn" profile ---
77 gluetun:
78 image: qmcgaw/gluetun:latest
79 container_name: gluetun-skunky
80 profiles: ["vpn"]
81 cap_add:
82 - NET_ADMIN
83 devices:
84 - /dev/net/tun:/dev/net/tun
85 ports:
86 - "127.0.0.1:8888:8888" # host-side, only for testing the proxy
87 environment:
88 # Provider + tunnel type — your choice (see gluetun wiki).
89 - VPN_SERVICE_PROVIDER=${VPN_SERVICE_PROVIDER:-}
90 - VPN_TYPE=${VPN_TYPE:-wireguard}
91 # WireGuard credentials (leave PRESHARED empty if your provider omits it).
92 - WIREGUARD_PRIVATE_KEY=${VPN_PRIVATE_KEY:-}
93 - WIREGUARD_PRESHARED_KEY=${VPN_PRESHARED_KEY:-}
94 - WIREGUARD_ADDRESSES=${VPN_ADDRESSES:-}
95 - SERVER_COUNTRIES=${VPN_COUNTRIES:-}
96 - HTTPPROXY=on # built-in HTTP proxy on :8888
97 - TZ=${TZ:-Etc/UTC}
98 # If skunky can't reach the proxy while gluetun is healthy, uncomment to let
99 # gluetun's firewall accept the docker network:
100 # - FIREWALL_OUTBOUND_SUBNETS=172.16.0.0/12
101 restart: unless-stopped