├── .gitignore ├── deploy ├── secrets └── acme_dns_credentials.env ├── proxy ├── configuration.nix ├── linode.nix ├── hardware-configuration.nix └── nginx │ ├── public │ └── index.html │ └── default.nix ├── network.nix ├── ssh_keys.nix ├── .github └── workflows │ ├── test.yml │ └── deploy.yml ├── LICENSE.md ├── README.md └── rules.nix /.gitignore: -------------------------------------------------------------------------------- 1 | /.gcroots/ 2 | /secrets/ 3 | -------------------------------------------------------------------------------- /deploy: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env nix-shell 2 | #! nix-shell -p morph -i bash 3 | 4 | morph deploy ./network.nix --keep-result switch $@ 5 | -------------------------------------------------------------------------------- /secrets/acme_dns_credentials.env: -------------------------------------------------------------------------------- 1 | # This file contains the credentials for ACME to automatically create a DNS TXT 2 | # record to automatically create and renew wildcard certificates for us, so we 3 | # don't have to worry about tons of tiny certificates being reviewed. 4 | DNSIMPLE_OAUTH_TOKEN= 5 | -------------------------------------------------------------------------------- /proxy/configuration.nix: -------------------------------------------------------------------------------- 1 | { pkgs, lib, ... }: { 2 | imports = [ 3 | ./hardware-configuration.nix 4 | 5 | ./linode.nix # there are some networking config items in here 6 | 7 | # Services 8 | ./nginx 9 | ]; 10 | 11 | boot.cleanTmpDir = true; 12 | 13 | networking.hostName = "proxy"; 14 | networking.firewall.allowPing = true; 15 | 16 | services.openssh.enable = true; 17 | users.users.root.openssh.authorizedKeys.keys = 18 | lib.flatten (builtins.attrValues (import ../ssh_keys.nix)); 19 | } 20 | -------------------------------------------------------------------------------- /network.nix: -------------------------------------------------------------------------------- 1 | { 2 | network.description = "proxy deployment on Linode"; 3 | 4 | "proxy" = { config, pkgs, lib, ... }: { 5 | deployment = { 6 | targetUser = "root"; 7 | targetHost = "proxy.servers.hackclub.com"; 8 | 9 | secrets = { 10 | "acme-dns-credentials" = { 11 | source = "./secrets/acme_dns_credentials.env"; 12 | destination = "/var/secrets/acme_dns_credentials.env"; 13 | }; 14 | }; 15 | }; 16 | 17 | imports = [ ./proxy/configuration.nix ]; 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /proxy/linode.nix: -------------------------------------------------------------------------------- 1 | # These are recommended (needed?) configuration options when running NixOS on 2 | # Linode. From https://www.linode.com/docs/guides/install-nixos-on-linode/. 3 | { pkgs, ... }: { 4 | networking.useDHCP = false; 5 | networking.interfaces.eth0.useDHCP = true; 6 | networking.interfaces.eth0.tempAddress = 7 | "disabled"; # needed for ipv6 to work on Linode, https://github.com/NixOS/nixpkgs/issues/71273#issuecomment-545442741 8 | 9 | networking.usePredictableInterfaceNames = false; # needed for linode 10 | 11 | environment.systemPackages = with pkgs; [ inetutils mtr sysstat ]; 12 | } 13 | -------------------------------------------------------------------------------- /proxy/hardware-configuration.nix: -------------------------------------------------------------------------------- 1 | { modulesPath, ... }: { 2 | imports = [ (modulesPath + "/profiles/qemu-guest.nix") ]; 3 | 4 | nixpkgs.hostPlatform = "x86_64-linux"; 5 | 6 | boot.initrd.kernelModules = [ "nvme" ]; 7 | 8 | fileSystems."/" = { 9 | device = "/dev/sda"; 10 | fsType = "ext4"; 11 | }; 12 | 13 | boot.kernelParams = [ "console=ttyS0,19200n8" ]; 14 | boot.loader.grub.extraConfig = '' 15 | serial --speed=19200 --unit=0 --word=8 --parity=no --stop=1; 16 | terminal_input serial; 17 | terminal_output serial 18 | ''; 19 | 20 | boot.loader.grub.forceInstall = true; 21 | boot.loader.grub.device = "nodev"; 22 | boot.loader.timeout = 10; 23 | } 24 | -------------------------------------------------------------------------------- /ssh_keys.nix: -------------------------------------------------------------------------------- 1 | { 2 | zrl = [ 3 | "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEwQfzs4sQYgvcVKlWFbBKPmFH1yPFBGi4lJMrIlYm/5 zrl@lugia" 4 | "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICSLDfNoAhyP89I99ZgepL6LiZE2jK6A4cqGR4CNceUb zrl@psyduck" 5 | "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIDO1VSoHnkHOK3ZCqqCRCxtzVtEFast1EWKgFne3tnN zrl@abra" 6 | ]; 7 | 8 | msw = [ 9 | "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII5bJhhyjxGBe/3cU7NzbLBuX6hFn+nkgx3HD/nNDf4B max@rubber" 10 | ]; 11 | 12 | cheru = [ 13 | "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBzyhw0uZVE2mv1fdIcQH/91HkYlCLgSwvx34Ld7yn1t" 14 | ]; 15 | 16 | github-actions = [ 17 | "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL4/L67pKMn7tk24rjTUOSVW7Zk70+bXS7zlaV956pSU proxy@github-actions" 18 | ]; 19 | } 20 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | # Note: Proxy does not have a test suite, this just checks to see if the 2 | # deployment will build to catch any compile-time errors. 3 | name: "Check for syntax and configuration errors" 4 | 5 | on: 6 | pull_request: 7 | 8 | jobs: 9 | test: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: "Checkout hackclub/proxy" 13 | uses: actions/checkout@v2.3.4 14 | - name: "Install Nix" 15 | uses: cachix/install-nix-action@v13 16 | with: 17 | nix_path: nixpkgs=channel:nixos-unstable 18 | - name: "Enable nix-command experimental feature (needed for Morph)" 19 | run: mkdir -p ~/.config/nix && echo "experimental-features = nix-command" >> ~/.config/nix/nix.conf 20 | - name: "Build the deployment to see if there are any syntax or configuration errors that can be caught at compile time" 21 | run: nix-shell -p morph --run "morph build network.nix" 22 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License 2 | 3 | Copyright 2021 The Hack Foundation / Hack Club 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: "Deploy to proxy.servers.hackclub.com" 2 | 3 | on: 4 | push: 5 | branches: 6 | - 'main' 7 | 8 | jobs: 9 | deploy: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: "Checkout hackclub/proxy" 13 | uses: actions/checkout@v2.3.4 14 | - name: "Install Nix" 15 | uses: cachix/install-nix-action@v13 16 | with: 17 | nix_path: nixpkgs=channel:nixos-unstable 18 | - name: "Enable nix-command experimental feature (needed for Morph)" 19 | run: mkdir -p ~/.config/nix && echo "experimental-features = nix-command" >> ~/.config/nix/nix.conf 20 | - name: "Install SSH key for deployment" 21 | uses: webfactory/ssh-agent@v0.5.3 22 | with: 23 | ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }} 24 | - name: "Set known host info for proxy.servers.hackclub.com" 25 | run: echo "proxy.servers.hackclub.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJ0IXOb9Yq8W03JX2AFe1j07LVOMNdcXXP9yCkmFvvvK" >> ~/.ssh/known_hosts 26 | - name: "Build and deploy to proxy.servers.hackclub.com" 27 | run: ./deploy 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # proxy server + NixOS = proxyparty! 2 | 3 | You've found a pass to the proxy party! 4 | 5 | Ever need to redirect one URL to another? Ever need to proxy a website to a different domain? Hate manually configuring nginx? 6 | 7 | This is Hack Club's proxy server, which we rely on to make sure our old links keep working, that certain domains are proxied to different domains to get around school filters, and that any needed redirects are easy to set up and manage. 8 | 9 | Here's how it works: 10 | 11 | 1. Open up `rules.nix` and add a new rule to either redirect, permanently redirect, or proxy one URL to another 12 | 2. Make sure the domain you want to redirect from / proxy to points to `proxyparty.hackclub.com` (most Hack Club domains have a subdomain wildcard that points to this server, see [`hackclub/dns`](https://github.com/hackclub/dns)) 13 | 3. Submit a pull request with your changes 14 | 15 | Orpheus at a proxy party admissions booth 16 | 17 | And that's it! Once your pull request is merged, a new nginx configuration with your changes is automatically generated, and the server at `proxyparty.hackclub.com` is automatically updated using GitHub Actions. 18 | 19 | It’ll even get an SSL certificate if one doesn’t already exist for the domain, and automatically renew any SSL certificates when it’s time. It's almost like magic, thanks to the power of NixOS! 20 | 21 | ## License 22 | 23 | proxyparty is licensed under the [MIT License](LICENSE.md)! 24 | -------------------------------------------------------------------------------- /proxy/nginx/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | proxyparty - hack club 5 | 6 | 7 |
 8 | ppppp   ppppppppp   rrrrr   rrrrrrrrr      ooooooooooo xxxxxxx      xxxxxxxyyyyyyy           yyyyyyy
 9 | p::::ppp:::::::::p  r::::rrr:::::::::r   oo:::::::::::oox:::::x    x:::::x  y:::::y         y:::::y
10 | p:::::::::::::::::p r:::::::::::::::::r o:::::::::::::::ox:::::x  x:::::x    y:::::y       y:::::y
11 | pp::::::ppppp::::::prr::::::rrrrr::::::ro:::::ooooo:::::o x:::::xx:::::x      y:::::y     y:::::y
12 |  p:::::p     p:::::p r:::::r     r:::::ro::::o     o::::o  x::::::::::x        y:::::y   y:::::y
13 |  p:::::p     p:::::p r:::::r     rrrrrrro::::o     o::::o   x::::::::x          y:::::y y:::::y
14 |  p:::::p     p:::::p r:::::r            o::::o     o::::o   x::::::::x           y:::::y:::::y
15 |  p:::::p    p::::::p r:::::r            o::::o     o::::o  x::::::::::x           y:::::::::y
16 |  p:::::ppppp:::::::p r:::::r            o:::::ooooo:::::o x:::::xx:::::x           y:::::::y
17 |  p::::::::::::::::p  r:::::r            o:::::::::::::::ox:::::x  x:::::x           y:::::y
18 |  p::::::::::::::pp   r:::::r             oo:::::::::::oox:::::x    x:::::x         y:::::y
19 |  p::::::pppppppp     rrrrrrr               ooooooooooo xxxxxxx      xxxxxxx       y:::::y
20 |  p:::::p                                                                         y:::::y
21 |  p:::::p                                                                        y:::::y
22 | p:::::::p                                                                      y:::::y
23 | p:::::::p                                                                     y:::::y
24 | p:::::::p                                                                    yyyyyyy
25 | ppppppppp
26 | 
27 | 
28 | you have stumbled upon proxyparty! i am a server that does HTTP redirects and
29 | occasional proxying of traffic for hack club, the most delightful group of high
30 | school hackers on the planet!
31 | 
32 | check out and contribute to my source code at https://github.com/hackclub/proxyparty
33 |     
34 | 35 | 36 | -------------------------------------------------------------------------------- /proxy/nginx/default.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ... }: 2 | let 3 | rules = import ../../rules.nix; 4 | 5 | acmeEmail = "team@hackclub.com"; 6 | dnsProvider = "dnsimple"; 7 | dnsCredentialsFile = "/var/secrets/acme_dns_credentials.env"; 8 | proxyDomain = "proxyparty.hackclub.com"; # URL of this server 9 | domains = [ 10 | "hackclub.com" 11 | "hack.af" 12 | "hackclub.org" 13 | "bulckcah.com" 14 | "hackclub.io" 15 | "hackedu.us" 16 | "scrapbook.dev" 17 | "scrap.dev" 18 | "hackclub.money" 19 | "dino.icu" 20 | "wackclub.com" 21 | # "hackclub.us" 22 | ]; 23 | 24 | # given a virtual host name, return the domain that matches 25 | # 26 | # ex. domainForHost 'foo.hackclub.com' -> 'hackclub.com' 27 | domainForHost = with lib; 28 | with builtins; 29 | host: 30 | findFirst (d: hasSuffix d host) 31 | (abort "Could not find matching domain for ${host}") domains; 32 | 33 | # from https://stackoverflow.com/a/54505212 34 | recursiveMerge = with lib; 35 | attrList: 36 | let 37 | f = attrPath: 38 | zipAttrsWith (n: values: 39 | if tail values == [ ] then 40 | head values 41 | else if all isList values then 42 | unique (concatLists values) 43 | else if all isAttrs values then 44 | f (attrPath ++ [ n ]) values 45 | else 46 | last values); 47 | in f [ ] attrList; 48 | 49 | rulesConfig = recursiveMerge (map (rule: 50 | if builtins.hasAttr "redirect" rule then { 51 | services.nginx.virtualHosts."${rule.redirect}" = { 52 | forceSSL = true; 53 | useACMEHost = domainForHost rule.redirect; 54 | 55 | locations."/".return = "302 ${rule.dest}${ 56 | if rule ? "stripArgs" then "" else "$is_args$args" 57 | }"; 58 | }; 59 | } else if builtins.hasAttr "permRedirect" rule then { 60 | services.nginx.virtualHosts."${rule.permRedirect}" = { 61 | forceSSL = true; 62 | useACMEHost = domainForHost rule.permRedirect; 63 | 64 | locations."/".return = "302 ${rule.dest}${ 65 | if rule ? "stripArgs" then "" else "$is_args$args" 66 | }"; 67 | }; 68 | } else if builtins.hasAttr "proxy" rule then { 69 | services.nginx.virtualHosts."${rule.proxy}" = { 70 | forceSSL = true; 71 | useACMEHost = domainForHost rule.proxy; 72 | 73 | locations."/" = { 74 | proxyPass = "${rule.dest}$request_uri"; 75 | proxyWebsockets = true; 76 | 77 | extraConfig = '' 78 | # required per https://stackoverflow.com/a/22259088 79 | resolver 1.1.1.1; 80 | 81 | # required when the destination is also a TLS server with multiple hosts 82 | proxy_ssl_server_name on; 83 | ''; 84 | }; 85 | }; 86 | } else 87 | abort "Can't find 'proxy', 'redirect', or 'permRedirect' in ${ 88 | builtins.toJSON rule 89 | }") rules); 90 | in recursiveMerge [ 91 | { 92 | networking.firewall.allowedTCPPorts = [ 80 443 ]; 93 | 94 | services.nginx = { 95 | enable = true; 96 | 97 | recommendedTlsSettings = true; 98 | recommendedGzipSettings = true; 99 | recommendedOptimisation = true; 100 | 101 | # subdomain catch-alls for all domains 102 | virtualHosts = recursiveMerge [ 103 | (with builtins; 104 | listToAttrs (map (domain: { 105 | name = "*.${domain}"; 106 | value = { 107 | forceSSL = true; 108 | useACMEHost = domain; 109 | 110 | serverName = 111 | let escapedDomain = (replaceStrings [ "." ] [ "\\." ] domain); 112 | in "~^(?P.+\\.)${escapedDomain}$"; 113 | 114 | locations."/".return = "302 https://hackclub.com"; 115 | }; 116 | }) domains)) 117 | 118 | { 119 | "${proxyDomain}" = { 120 | default = true; 121 | 122 | locations."/".root = ./public; 123 | }; 124 | } 125 | ]; 126 | }; 127 | 128 | users.users.nginx.extraGroups = [ "acme" ]; 129 | 130 | # generate wildcard certificates for all the domains 131 | security.acme = { 132 | acceptTerms = true; 133 | email = acmeEmail; 134 | certs = builtins.listToAttrs (map (domain: { 135 | name = domain; 136 | value = { 137 | dnsProvider = dnsProvider; 138 | credentialsFile = dnsCredentialsFile; 139 | extraDomainNames = [ "*.${domain}" ]; # get wildcard certs 140 | }; 141 | }) domains); 142 | }; 143 | } 144 | rulesConfig 145 | ] 146 | -------------------------------------------------------------------------------- /rules.nix: -------------------------------------------------------------------------------- 1 | # proxy = proxy the traffic through to the dest 2 | # redirect = 302 redirect the traffic to the dest, passing the request_uri (the ?foobar portion of the URL) (you probably want this) 3 | # permRedirect = 301 redirect to the dest 4 | # 5 | # you can optionally set `stripArgs` to true to not pass the request URI to dest. 6 | # example without stripArgs set: gh.hackclub.com/foobar?hello=there -> https://github.com/hackclub/hackclub/foobar?hello=there 7 | # example with stripArgs set: gh.hackclub.com/foobar -> https://github.com/hackclub/hackclub/foobar 8 | [ 9 | { 10 | redirect = "admin.hackclub.com"; 11 | dest = "https://hackclub.com/admin"; 12 | } 13 | 14 | { 15 | proxy = "scrap.dev"; 16 | dest = "https://scrapbook.hackclub.com"; 17 | } 18 | 19 | { 20 | proxy = "scrapbook.dev"; 21 | dest = "https://scrapbook.hackclub.com"; 22 | } 23 | 24 | { 25 | redirect = "hackclub.money"; 26 | dest = "https://hcb.hackclub.com"; 27 | } 28 | 29 | { 30 | redirect = "sprig.hackclub.org"; 31 | dest = "https://hack.af/sprig-for-hackers"; 32 | } 33 | 34 | { 35 | redirect = "floppy.hackclub.com"; 36 | dest = "http://dinobox.local:3000"; 37 | } 38 | 39 | { 40 | proxy = "bulckcah.com"; 41 | dest = "https://hackclub.com"; 42 | } 43 | { 44 | proxy = "workshops.bulckcah.com"; 45 | dest = "https://workshops.hackclub.com"; 46 | } 47 | { 48 | proxy = "api.bulckcah.com"; 49 | dest = "https://api.hackclub.com"; 50 | } 51 | { 52 | proxy = "toolbox.bulckcah.com"; 53 | dest = "https://toolbox.hackclub.com"; 54 | } 55 | { 56 | proxy = "school-toolbox.bulckcah.com"; 57 | dest = "https://school-toolbox.hackclub.com"; 58 | } 59 | { 60 | proxy = "blot.bulckcah.com"; 61 | dest = "https://blot.hackclub.com"; 62 | } 63 | { 64 | proxy = "sprig.bulckcah.com"; 65 | dest = "https://sprig.hackclub.com"; 66 | } 67 | { 68 | proxy = "blot.wackclub.com"; 69 | dest = "https://blot.hackclub.com"; 70 | } 71 | { 72 | proxy = "sprig.wackclub.com"; 73 | dest = "https://sprig.hackclub.com"; 74 | } 75 | { 76 | redirect = "blog.hackclub.com"; 77 | dest = "https://hackclub.com"; 78 | } 79 | { 80 | redirect = "board.hackclub.com"; 81 | dest = "https://github.com/orgs/hackclub/projects/6"; 82 | } 83 | { 84 | permRedirect = "camp-sheet.hackclub.com"; 85 | dest = 86 | "https://docs.google.com/spreadsheets/d/1HCh5YtN_Y3JXbIMoiUdv-FgYiPZZD1kGg5QnfbsxiCw/edit"; 87 | } 88 | 89 | { 90 | redirect = "camp.hackedu.us"; 91 | dest = "https://camp.hackclub.com"; 92 | } 93 | { 94 | redirect = "camp.hackclub.io"; 95 | dest = "https://camp.hackclub.com"; 96 | } 97 | 98 | { 99 | redirect = "chicagohacks.hackclub.com"; 100 | dest = "https://max68.typeform.com/to/IgeAc1"; 101 | } 102 | 103 | { 104 | redirect = "clubs.hackedu.us"; 105 | dest = 106 | "https://docs.google.com/spreadsheets/d/1Mb-8WBjiZUOYgWqNJxaigCWZvZqnIHZ2ZhokVNCbJ4g"; 107 | } 108 | { 109 | redirect = "clubs.hackclub.io"; 110 | dest = 111 | "https://docs.google.com/spreadsheets/d/1Mb-8WBjiZUOYgWqNJxaigCWZvZqnIHZ2ZhokVNCbJ4g"; 112 | } 113 | { 114 | redirect = "clubs.hackclub.com"; 115 | dest = 116 | "https://docs.google.com/spreadsheets/d/1Mb-8WBjiZUOYgWqNJxaigCWZvZqnIHZ2ZhokVNCbJ4g"; 117 | } 118 | 119 | { 120 | redirect = "conduct.hackclub.com"; 121 | dest = "https://hackclub.com/conduct/"; 122 | } 123 | { 124 | redirect = "deals.hackclub.com"; 125 | dest = "https://github.com/hackclub/deals"; 126 | } 127 | { 128 | redirect = "demo-night.hackclub.com"; 129 | dest = 130 | "https://www.eventbrite.com/e/hack-club-demo-night-tickets-26838356246"; 131 | } 132 | { 133 | proxy = "design.hackclub.com"; 134 | dest = "https://hackclub.github.io/design-system"; 135 | } 136 | { 137 | redirect = "donate.hackedu.us"; 138 | dest = "https://hackclub.com/donate"; 139 | } 140 | { 141 | redirect = "donate.hackclub.io"; 142 | dest = "https://hackclub.com/donate"; 143 | } 144 | { 145 | redirect = "donate.hackclub.com"; 146 | dest = "https://hackclub.com/donate"; 147 | } 148 | { 149 | redirect = "dropbox.hackclub.com"; 150 | dest = "https://www.dropbox.com/request/v4iO3DcN6BdYF7b5h1PT"; 151 | } 152 | { 153 | redirect = "feedback.hackedu.us"; 154 | dest = "https://labs.hackclub.com"; 155 | } 156 | { 157 | redirect = "feedback.hackclub.io"; 158 | dest = "https://labs.hackclub.com"; 159 | } 160 | { 161 | redirect = "feedback.hackclub.com"; 162 | dest = "https://labs.hackclub.com"; 163 | } 164 | { 165 | redirect = "find.hackclub.com"; 166 | dest = "https://finder.hackclub.com"; 167 | } 168 | { 169 | proxy = "finder.hackclub.com"; 170 | dest = "https://finder.netlify.com"; 171 | } 172 | { 173 | redirect = "gh.hackclub.com"; 174 | dest = "https://github.com/hackclub/hackclub"; 175 | stripArgs = true; 176 | } 177 | { 178 | redirect = "guide.hackclub.com"; 179 | dest = "https://hackclub.atlassian.net/servicedesk/customer/"; 180 | } 181 | 182 | { 183 | redirect = "hack-camp-playbook.hackedu.us"; 184 | dest = 185 | "https://github.com/hackclub/hack-camp/tree/master/cohort_4/playbook"; 186 | } 187 | { 188 | redirect = "hack-camp-playbook.hackclub.io"; 189 | dest = 190 | "https://github.com/hackclub/hack-camp/tree/master/cohort_4/playbook"; 191 | } 192 | { 193 | redirect = "hack-camp-playbook.hackclub.com"; 194 | dest = 195 | "https://github.com/hackclub/hack-camp/tree/master/cohort_4/playbook"; 196 | } 197 | 198 | { 199 | redirect = "hackedu.us"; 200 | dest = "https://hackclub.com"; 201 | } 202 | { 203 | redirect = "hackclub.io"; 204 | dest = "https://hackclub.com"; 205 | } 206 | { 207 | redirect = "hackclub.org"; 208 | dest = "https://hackclub.com"; 209 | } 210 | 211 | { 212 | redirect = "help.hackclub.com"; 213 | dest = "https://hackclub.atlassian.net/servicedesk/customer"; 214 | } 215 | { 216 | redirect = "idyllwild.hackclub.com"; 217 | dest = 218 | "https://docs.google.com/document/d/14V4NpORBH2VvFadUVV0Be1yYDrsjyYSAjUb1PZG5iSM/edit"; 219 | } 220 | { 221 | redirect = "internships.hackclub.com"; 222 | dest = 223 | "https://docs.google.com/spreadsheets/d/1dRuMVmmbTaR1hPm9pTQDMrCR4Vg4YuFhW2GsHEFcFxM/edit"; 224 | } 225 | 226 | { 227 | redirect = "irc.hackedu.us"; 228 | dest = 229 | "https://kiwiirc.com/client/irc.freenode.net/?nick=hacker|?#hack-club"; 230 | } 231 | 232 | { 233 | redirect = "partytime.hackclub.com"; 234 | dest = "https://zoom.us/s/6607256097"; 235 | } 236 | 237 | { 238 | proxy = "shipit.hackclub.com"; 239 | dest = "https://hackclub.github.io/shipit"; 240 | } 241 | { 242 | redirect = "shipped.hackclub.com"; 243 | dest = "https://github.com/hackclub/shipped"; 244 | } 245 | 246 | { 247 | redirect = "slack.hackclub.com"; 248 | dest = "https://hackclub.com/slack"; 249 | } 250 | 251 | { 252 | redirect = "sinerider.hackclub.com"; 253 | dest = "https://sinerider.com"; 254 | } 255 | 256 | { 257 | redirect = "dino.icu"; 258 | dest = "https://meta.dino.icu"; 259 | } 260 | 261 | { 262 | redirect = "pizza.hackclub.com"; 263 | dest = "https://hackclub.com/pizza"; 264 | } 265 | 266 | { 267 | redirect = "bin.hackclub.com"; 268 | dest = "https://hackclub.com/bin"; 269 | } 270 | 271 | { 272 | redirect = "high-seas.hackclub.com"; 273 | dest = "https://highseas.hackclub.com"; 274 | } 275 | ] 276 | --------------------------------------------------------------------------------