summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorluxagraf <sng@luxagraf.net>2018-10-12 09:12:07 -0500
committerluxagraf <sng@luxagraf.net>2018-10-12 09:12:07 -0500
commitfc250e225d17320351733ce47c940a41f1c04c6a (patch)
tree2d3b45e6e229ce3c85d8972be21d1e8611f692d6
parentd19e1290f938868d17bb16f0c6a91167f4ac7746 (diff)
added a bunch of new tutorials/notes on setting up my current server infrastructure.
-rw-r--r--set up awstats daily links.txt3
-rw-r--r--set up awstats on ubuntu with nginx.txt292
-rw-r--r--set up certbot nginx ubuntu.txt137
-rw-r--r--set up gitea on ubuntu 18.04.txt73
4 files changed, 505 insertions, 0 deletions
diff --git a/set up awstats daily links.txt b/set up awstats daily links.txt
new file mode 100644
index 0000000..9a2dd93
--- /dev/null
+++ b/set up awstats daily links.txt
@@ -0,0 +1,3 @@
+https://awstats.sourceforge.io/docs/awstats_faq.html#DAILY
+http://www.internetofficer.com/awstats/daily-stats/
+http://www.internetofficer.com/awstats/day-by-day/install/
diff --git a/set up awstats on ubuntu with nginx.txt b/set up awstats on ubuntu with nginx.txt
new file mode 100644
index 0000000..37a60ca
--- /dev/null
+++ b/set up awstats on ubuntu with nginx.txt
@@ -0,0 +1,292 @@
+If you'd like some basic data about your site's visitors, but don't want to let spyware vendors track them around the web, AWStats makes a good solution. It parses your server log files and tells you who came by and what they did. There's no spying, no third-party code bloat. AWStats just analyzes your visitors' footprints.
+
+Here's how I got AWStats up and running on an Ubuntu 18.04 VPS server running over at [Vultr.com](https://www.vultr.com/?ref=6825229) ([non-affiliate link](https://www.vultr.com/) if you prefer).
+
+### AWStats with GeoIP
+
+The first step is to install the AWStats package from the Ubuntu repositories:
+
+~~~~console
+sudo apt install awstats
+~~~~
+
+This will install the various tools and scripts AWStats needs. Because I like to have some geodata in my stats, I also installed the tools necessary to use the AWStats geoip plugin. Here's what worked for me.
+
+First we need build-essential and libgeoip:
+
+~~~~console
+sudo apt install libgeoip-dev build-essential
+~~~~
+
+Next you need to fire up the cpan shell:
+
+~~~~console
+cpan
+~~~~
+
+If this is your first time in cpan you'll need to run two commands to get everything set up. If you've already got cpan set up, you can skip to the next step:
+
+~~~~perl
+make install
+install Bundle::CPAN
+~~~~
+
+Once cpan is set up, install GeoIP:
+
+~~~~perl
+install Geo::IP
+~~~~
+
+That should take care of the GeoIP stuff. You can double-check that the database files exist by looking in the directory `/usr/share/GeoIP/` and verifying that there's a file named `GeoIP.dat`.
+
+Now, on to the log file setup.
+
+#### Optional Custom Nginx Log Format
+
+This part isn't strictly necessary. To get AWStats working the next step is to create our config files and build the stats, but first I like to overcomplicate things with a custom log format for Nginx. If you don't customize your Nginx log format then you can skip this section, but make a note of where Nginx is putting your logs, you'll need that in the next step.
+
+Open up `/etc/nginx/nginx.conf` and add these lines:
+
+~~~~nginx
+log_format main '$remote_addr - $remote_user [$time_local] "$request" '
+ '$status $body_bytes_sent "$http_referer" '
+ '"$http_user_agent" "$http_x_forwarded_for"';
+~~~~
+
+Now we need to edit our individual nginx config file to use this log format. If you follow the standard nginx practice, your config file should be in `/etc/nginx/sites-enabled/`. For example this site is served by the file `/etc/nginx/sites-enabled/luxagraf.net.conf`. Wherever that file may be in your setup, open it and add this line somewhere in the `server` block.
+
+~~~~nginx
+server {
+ # ... all your other config ...
+ access_log /var/log/nginx/yourdomain.com.access.log main;
+ # ... all your other config ...
+}
+~~~~
+
+### Configure AWStats for Nginx
+
+As I said in the beginning, AWStats is ancient, it hails from a very different era of the internet. One legacy from the olden days is that AWStats is very strict about configuration files. You have to have one config file per domain you're tracking and that file has to be named in the following way: `awstats.domain.tld.conf`. Those config files must be placed inside the /etc/awstats/ directory.
+
+If you go take a look at the `/etc/awstats` directory you'll see two files in there: `awstats.conf` and `awstats.conf.local`. The first is a main conf file that serves as a fallback if your own config file doesn't specify a particular setting. The second is an empty file that's meant to be used to share common config settings, which really doesn't make much sense to me.
+
+I took a tip from [this tutorial](https://kamisama.me/2013/03/20/install-configure-and-protect-awstats-for-multiple-nginx-vhost-on-debian/) and dumped the contents of awstats.conf into awstats.local.conf. That way my actual site config file is very short. If you want to do that, then all you have to put in your config file are a few lines.
+
+Using the naming scheme mentioned above, my config file resides at `/etc/awstats/awstats.luxagraf.net.conf` and it looks like this (drop your actual domain in place of "yourdomain.com"):
+
+~~~~ini
+# Path to your nginx log file
+LogFile="/var/log/nginx/yourdomain.com.access.log"
+
+# Domain of your vhost
+SiteDomain="yourdomain.com"
+
+# Directory where to store the awstats data
+DirData="/var/lib/awstats/"
+
+# Other domains/subdomain you want included from your logs, for example the www subdomain
+HostAliases="www.yourdomain.com"
+
+# If you customized your log format above add this line:
+
+LogFormat = "%host - %host_r %time1 %methodurl %code %bytesd %refererquot %uaquot %otherquot"
+
+# If you did not, uncomment and use this line:
+# LogFormat = 1
+~~~~
+
+Save that file and open the fallback file `awstats.conf.local`. Now set a few things:
+
+~~~~ini
+# if your site doesn't get a lot of traffic you can leave this at 1
+# but it can make things slow
+DNSLookup = 0
+
+# find the geoip plugin line and uncomment it:
+LoadPlugin="geoip GEOIP_STANDARD /usr/share/GeoIP/GeoIP.dat"
+~~~~
+
+Then delete the LogFile, SiteDomain, DirData, and HostAliases settings in your `awstats.conf.local` file. We've got those covered in our site-specific config file.
+
+Okay, that's it for configuring things, let's generate some data to look at.
+
+### Building Stats and Rotating Log Files
+
+Now that we have our log files, and we've told AWStats where they are, what format they're in and where to put its analysis, it's time to actually run AWStats and get the raw data analyzed. To do that we use this command:
+
+~~~~console
+sudo /usr/lib/cgi-bin/awstats.pl -config=yourdoamin.com -update
+~~~~
+
+Alternately, if you have a bunch of config files you'd like to update all at once, you can use this wrapper script conveniently located in a completely different directory:
+
+~~~~console
+/usr/share/doc/awstats/examples/awstats_updateall.pl now -awstatsprog=/usr/lib/cgi-bin/awstats.pl
+~~~~
+
+You're going to need to run that command regularly to update the AWStats data. One way to do is with a crontab entry, but there are better ways to do this. Instead of cron we can hook into logrotate, which rotates Nginx's log files periodically anyway and conveniently includes a `prerotate` directive that we can use to execute some code. Technically logrotate runs via /etc/cron.daily under the hood, so we haven't really escaped cron, but it's not a crontab we need to keep track of anyway.
+
+~~~~log
+Open up the file `/etc/logrotate.d/nginx` and replace it with this:
+
+ /var/log/nginx/*.log{
+ daily
+ missingok
+ rotate 30
+ compress
+ delaycompress
+ notifempty
+ create 0640 www-data adm
+ sharedscripts
+ prerotate
+ /usr/share/doc/awstats/examples/awstats_updateall.pl now -awstatsprog=/usr/lib/cgi-bin/awstats.pl
+ if [ -d /etc/logrotate.d/httpd-prerotate ]; then \
+ run-parts /etc/logrotate.d/httpd-prerotate; \
+ fi \
+ endscript
+ postrotate
+ invoke-rc.d nginx rotate >/dev/null 2>&1
+ endscript
+ }
+~~~~
+
+The main things we've changed here are the frequency, moving from weekly to daily rotation in line 2, keeping 30 days worth of logs in line 4, and then calling AWStats in line 11.
+
+One thing to bear in mind is that if you re-install Nginx for some reason this file will be overwritten.
+
+Now do a dry run to make sure you don't have any typos or other problems:
+
+~~~~console
+sudo logrotate -f /etc/logrotate.d/nginx
+~~~~
+
+### Serving Up AWStats
+
+Now that all the pieces are in place, we need to put our stats on the web. I used a subdomain, awstats.luxagraf.net. Assuming you're using something similar here's an nginx config file to get you started:
+
+~~~~nginx
+server {
+ server_name awstats.luxagraf.net;
+
+ root /var/www/awstats.luxagraf.net;
+ error_log /var/log/nginx/awstats.luxagraf.net.error.log;
+ access_log off;
+ log_not_found off;
+
+ location ^~ /awstats-icon {
+ alias /usr/share/awstats/icon/;
+ }
+
+ location ~ ^/cgi-bin/.*\\.(cgi|pl|py|rb) {
+ auth_basic "Admin";
+ auth_basic_user_file /etc/awstats/awstats.htpasswd;
+
+ gzip off;
+ include fastcgi_params;
+ fastcgi_pass unix:/var/run/php/php7.2-fpm.sock; # change this line if necessary
+ fastcgi_index cgi-bin.php;
+ fastcgi_param SCRIPT_FILENAME /etc/nginx/cgi-bin.php;
+ fastcgi_param SCRIPT_NAME /cgi-bin/cgi-bin.php;
+ fastcgi_param X_SCRIPT_FILENAME /usr/lib$fastcgi_script_name;
+ fastcgi_param X_SCRIPT_NAME $fastcgi_script_name;
+ fastcgi_param REMOTE_USER $remote_user;
+ }
+
+}
+~~~~
+
+This config is pretty basic, it passes requests for icons to the AWStats icon dir and then sends the rest of our requests to php-fpm. The only tricky part is that AWStats needs to call a Perl file, but we're calling a PHP file, namely `/etc/nginx/cgi-bin.php`. How's that work?
+
+Well, in a nutshell, this script takes all our server variables and passes them to stdin, calls the Perl script and then reads the response from stdout, passing it on to Nginx. Pretty clever, so clever in fact that I did not write it. Here's the file I use, taken straight from the Arch Wiki:
+
+~~~~php
+<?php
+$descriptorspec = array(
+ 0 => array("pipe", "r"), // stdin is a pipe that the child will read from
+ 1 => array("pipe", "w"), // stdout is a pipe that the child will write to
+ 2 => array("pipe", "w") // stderr is a file to write to
+);
+$newenv = $_SERVER;
+$newenv["SCRIPT_FILENAME"] = $_SERVER["X_SCRIPT_FILENAME"];
+$newenv["SCRIPT_NAME"] = $_SERVER["X_SCRIPT_NAME"];
+if (is_executable($_SERVER["X_SCRIPT_FILENAME"])) {
+ $process = proc_open($_SERVER["X_SCRIPT_FILENAME"], $descriptorspec, $pipes, NULL, $newenv);
+ if (is_resource($process)) {
+ fclose($pipes[0]);
+ $head = fgets($pipes[1]);
+ while (strcmp($head, "\n")) {
+ header($head);
+ $head = fgets($pipes[1]);
+ }
+ fpassthru($pipes[1]);
+ fclose($pipes[1]);
+ fclose($pipes[2]);
+ $return_value = proc_close($process);
+ } else {
+ header("Status: 500 Internal Server Error");
+ echo("Internal Server Error");
+ }
+} else {
+ header("Status: 404 Page Not Found");
+ echo("Page Not Found");
+}
+?>
+~~~~
+
+Save that mess of PHP as `/etc/nginx/cgi-bin.php` and then install php-fpm if you haven't already:
+
+~~~~console
+sudo apt install php-fpm
+~~~~
+
+Next we need to create the password file referenced in our Nginx config. We can create a .htpasswd file with this little shell command, just replace `yourdomain.com` with the same domain you used in your AWStats config and use an actual username in place of `username`:
+
+~~~~console
+printf "username:`openssl passwd -apr1`\n" >> awstats.htpasswd
+~~~~
+
+Enter your password when prompted and your password file will be created in the expected format for basic auth files.
+
+Then move that file to the proper directory:
+
+~~~~console
+sudo mv awstats.htpasswd /etc/awstats/
+~~~~
+
+Now we have an Nginx config, a script to pass AWStats from PHP to Perl and some basic password protection for our stats site. The last, totally optional, step is to serve it all over HTTPS instead of HTTP. Since we have a password protecting it anyway, this is arguably unnecessary. I do it more out of habit than any real desire for security. I mean, I did write an article [criticizing the push to make everything HTTPS](https://arstechnica.com/information-technology/2016/07/https-is-not-a-magic-bullet-for-web-security/). But habit.
+
+I have a separate guide on [how to set up Certbot for Nginx on Ubuntu 18.04](/src/certbot-nginx-ubuntu-1804) that you can follow. Once that's installed you can just invoke Certbot with:
+
+~~~~console
+sudo certbot --nginx
+~~~~
+
+Select the domain name you're serving your stats at (for me that's awstats.luxagraf.net), then select 2 to automatically redirect all traffic to HTTPS and certbot will append some lines to your Nginx config file.
+
+Now restart Nginx:
+
+~~~~console
+sudo systemctl restart nginx
+~~~~
+
+Visit your new site in the browser at this URL (changing yourdomain.com to the domains you've been using): [https://awstats.yourdomain.com/cgi-bin/cgi-bin.php?config=yourdomain.com](https://awstats.yourdomain.com/cgi-bin/cgi-bin.php?config=yourdomain.com). If all when well you should see AWStats with a few stats in it. If all did not go well, feel free to drop whatever your error message is in a comment here and I'll see if I can help.
+
+### Motivations
+
+And now the why. The "why the hell don't I just use --insert popular spyware here--" part.
+
+My needs are simple. I don't have ads. I don't have to prove to anyone how much traffic I get. And I don't really care how you got here. I don't care where you go after here. I hardly ever look at my stats.
+
+When I do look all I want to see is how many people stop by in a given month and if there's any one article that's getting a lot of visitors. I also enjoy seeing which countries visitors are coming from, though I recognize that VPNs make this information suspect.
+
+Since *I* don't track you I certainly don't want third-party spyware tracking you, so that means any hosted service is out. Now there are some self-hosted, open source spyware packages that I've used, Matomo being the best. It is nice, but I don't need or use most of what it offers. And I really dislike running MySQL on the cheap, underpowered VPS servers I use. It uses way too much memory. Unfortunately Matomo requires MySQL, as does Open Web Analytics.
+
+By process of elimination (no MySQL), and my very paltry requirements, the logical choice is a simple log analyzer. I went with AWStats because I'd used it in the past. Way in the past. But you know what, AWStats ain't broke. It doesn't spy. It uses no server resources. And it tells you 95 percent of what any spyware tool will tell you (provided you actually [read the documentation](http://www.awstats.org/docs/)).
+
+In the end, AWStats is good enough without being too much. But for something as simple as it is, AWStats is surprisingly complex to get up and running, which is what inspired this guide.
+
+##### Shoulders stood upon:
+
+* [AWStats Documentation](http://www.awstats.org/docs/awstats_config.html)
+* [Ubuntu Community Wiki: AWStats](https://help.ubuntu.com/community/AWStats)
+* [Arch Wiki: AWStats](https://wiki.archlinux.org/index.php/Awstats)
+* [Install, configure and protect Awstats for multiple nginx vhost on Debian](https://kamisama.me/2013/03/20/install-configure-and-protect-awstats-for-multiple-nginx-vhost-on-debian/)
diff --git a/set up certbot nginx ubuntu.txt b/set up certbot nginx ubuntu.txt
new file mode 100644
index 0000000..f13b1e9
--- /dev/null
+++ b/set up certbot nginx ubuntu.txt
@@ -0,0 +1,137 @@
+EFF's free certificate service, Certbot, has greatly simplified the task of setting up HTTPS for your websites. The only downside is that the certificates are only good for 90 days. Fortunately renewing is easy, and we can even automate it all with systemd. Here's how to set up Certbot with Nginx *and* make sure your SSL certs renew indefinitely with no input from you.
+
+This tutorial is aimed at anyone using an Ubuntu 18.04 VPS from cheap hosts like DigitalOcean or [Vultr.com](https://www.vultr.com/?ref=6825229), but should also work for other versions of Ubuntu, Debian, Fedora, CentOS and any other system that uses systemd. The only difference will be the commands you use to install Certbot. See the Certbot site for [instructions](https://certbot.eff.org/) specific to your system.
+
+Here's how you get Certbot running on Ubuntu 18.04, then we'll dive into setting up automatic renewals via systemd.
+
+You should not need this with 18.04, but to be on the safe side, make sure you have the `software-properties-common` package installed.
+
+~~~~console
+sudo apt install software-properties-common
+~~~~
+
+The next part requires that you add a PPA, my least favorite part of Certbot for Ubuntu, as I don't like to rely on PPAs for something as mission critical as my security certificates. Still, as of this writing, there is not a better way. At least go [look at the code](https://launchpad.net/~certbot/+archive/ubuntu/certbot) before you blindly cut and paste. When you're done, here's your cut and paste:
+
+~~~~console
+sudo apt update
+sudo add-apt-repository ppa:certbot/certbot
+sudo apt update
+sudo apt install python-certbot-nginx
+~~~~
+
+Now you're ready to install some certs. For this part I'm going to show the commands and the output of the commands since the `certbot` command is interactive. Note that the version below will append some lines to your Nginx config file. If you prefer to edit your config file yourself, use this command: `sudo certbot --nginx certonly`, otherwise, here's now to get your certs.
+
+~~~~console
+sudo certbot --nginx
+
+[sudo] password for $youruser:
+Saving debug log to /var/log/letsencrypt/letsencrypt.log
+Plugins selected: Authenticator nginx, Installer nginx
+
+Which names would you like to activate HTTPS for?
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+1: luxagraf.net
+2: awstats.luxagraf.net
+3: origin.luxagraf.net
+4: www.luxagraf.net
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Select the appropriate numbers separated by commas and/or spaces, or leave input blank to select all options shown (Enter 'c' to cancel): 4
+Obtaining a new certificate
+Performing the following challenges:
+http-01 challenge for www.luxagraf.net
+Waiting for verification...
+Cleaning up challenges
+Deploying Certificate to VirtualHost /etc/nginx/sites-enabled/luxagraf.net.conf
+
+Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+1: No redirect - Make no further changes to the webserver configuration.
+2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
+new sites, or if you're confident your site works on HTTPS. You can undo this
+change by editing your web server's configuration.
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
+
+Traffic on port 80 already redirecting to ssl in /etc/nginx/sites-enabled/luxagraf.net.conf
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Congratulations! You have successfully enabled https://www.luxagraf.net.
+You should test your configuration at: https://www.ssllabs.com/ssltest/analyze.html?d=www.luxagraf.net
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+IMPORTANT NOTES:
+ - Congratulations! Your certificate and chain have been saved at:
+ /etc/letsencrypt/live/www.luxagraf.net/fullchain.pem
+ Your key file has been saved at:
+ /etc/letsencrypt/live/www.luxagraf.net/privkey.pem
+ Your cert will expire on 2019-01-09. To obtain a new or tweaked
+ version of this certificate in the future, simply run certbot again
+ with the "certonly" option. To non-interactively renew *all* of
+ your certificates, run "certbot renew"
+ - If you like Certbot, please consider supporting our work by:
+ Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
+ Donating to EFF: https://eff.org/donate-le
+~~~~
+
+And there you have it, SSL certs for all your domains.
+
+That's all good and well, but those new certs are only good for 90 days. The odds of you remembering to renew that every 90 days -- even with reminder emails from the EFF -- is near nil. Plus, do you really want to be renewing certs by hand, [like an animal](http://5by5.tv/hypercritical/17)? No, you want to automate everything so you can do better things with your time.
+
+You could use cron, but the more modern approach would be to create a systemd service and a systemd timer to control when that service runs.
+
+I highly recommend reading through the Arch Wiki page on [systemd services and timers](https://wiki.archlinux.org/index.php/Systemd/Timers), as well as the [systemd.timer man pages](https://jlk.fjfi.cvut.cz/arch/manpages/man/systemd.timer.5) to get a better understanding of how you can automate other tasks in your system. But for the purposes of this tutorial all you really need to understand is that timers are just like other systemd unit files, but they include a `[Timer]` block which takes parameter for exactly when you want your service file to run.
+
+Timer files can live right next to your service files in `/etc/systemd/system/`.
+
+There's no hard and fast rules about naming timers, but it makes sense to use same name as the service file the timer controls, except the timer gets the `.timer` extension. So you'll have two files `myservice.service` and `myservice.timer`.
+
+Let's start with the service file. I call mine `certbot-renewal`. Open the service file:
+
+~~~~console
+sudo nano /etc/systemd/system/certbot-renewal.service
+~~~~
+
+This is going to be a super simple service, we'll give it a description and a command to run and that's it:
+
+~~~~ini
+[Unit]
+Description=Certbot Renewal
+
+[Service]
+ExecStart=/usr/bin/certbot renew
+~~~~
+
+Next we need to create a .timer file that will run the certbot.renewal service every day. Create this file:
+
+~~~~console
+sudo nano /etc/systemd/system/certbot-renewal.timer
+~~~~
+
+And now for the slightly more complex timer:
+
+~~~~ini
+[Unit]
+Description=Certbot Renewal Timer
+
+[Timer]
+OnBootSec=500
+OnUnitActiveSec=1d
+
+[Install]
+WantedBy=multi-user.target
+~~~~
+
+The `[Timer]` directive can take a number of parameters, the ones we've used constitute what's called a monotonic timer, which means they run "after a time span relative to a varying starting point". In other words they're not calendar events like cron.
+
+Our monotonic timer has two directives, `onBootSec` and `OnUnitActiveSec`. The first should be obvious, our timer will run 500 seconds after the system boots. Why 500? No real reason, I just didn't want to bog down the system at boot.
+
+The `OnUnitActiveSec` is really what makes this work. This directive measures time relative to when the service that the timer controls was last activated. In our case the `1d` means run the service one day after it last ran. So our timer will run once a day to make sure our scripts stay up to date.
+
+As a kind of footnote, in systemd parlance calendar-based timers are called realtime timers and can be used to replace cron if you want, though there are some disadvantages, see the Arch Wiki for [a good overview of what you get and what you lose](https://wiki.archlinux.org/index.php/Systemd/Timers#As_a_cron_replacement) if you go that route.
+
+Okay, the last step for our certbot renewal system is to enable and then start our timer. Note that we don't have to do either to our actual service file because we don't want it active, the timer will control when it runs.
+
+~~~~console
+sudo systemctl enable certbot-renewal.timer
+sudo systemctl start certbot-renewal.timer
+~~~~
+
+Run those commands and you're done. Your timer is now active and your Certbot certificates will automatically renew as long as your server is up and running.
diff --git a/set up gitea on ubuntu 18.04.txt b/set up gitea on ubuntu 18.04.txt
new file mode 100644
index 0000000..8a031b0
--- /dev/null
+++ b/set up gitea on ubuntu 18.04.txt
@@ -0,0 +1,73 @@
+The first things to do is isolate gitea a bit, running it under a different user seems to be the standard practice. Installing Gitea via the Arch User Repository will create a `git` user, so that's what I used on Ubuntu 18.04 as well.
+
+Here's a shell command to do that:
+
+~~~~console
+sudo adduser --system --shell /bin/bash --group --disabled-password --home /home/git git
+~~~~
+
+This is pretty much a standard adduser command like you'd use when setting up a new VPS, the only difference is that we've added the `--disable-password` flag so you can't actually log in with it. That's a bit more secure and we won't be logging in with it.
+
+At the time of writing that's version 1.5.2, but be sure check the downloads page for the latest version and adjust the commands below to work with that version number. Let's download the Gitea binary and then we'll verify the signing key Verifying keys is very important when working with binaries since you can't see the code behind them[^1].
+
+~~~~console
+wget -O gitea https://dl.gitea.io/gitea/1.5.2/gitea-1.5.2-linux-amd64
+gpg --keyserver pgp.mit.edu --recv 0x2D9AE806EC1592E2
+wget https://dl.gitea.io/gitea/1.5.2/gitea-1.5.2-linux-amd64.asc
+gpg --verify gitea-1.5.2-linux-amd64.asc gitea
+~~~~
+
+A couple of notes here, gpg should say the keys match, but then it should also warn that "this key is not certified with a trusted signature!" That means, essentially, that this binary could have been signed by anybody. That should make you nervous, but at least we know it wasn't tampered with in transit[^1].
+
+Now let's make the binary executable and test it to make sure it's working:
+
+~~~~console
+chmod +x gitea
+./gitea web
+~~~~
+
+You can stop Gitea with `Ctrl+C`. Let's move the binary to a more traditional location:
+
+~~~~console
+sudo cp gitea /usr/local/bin/gitea
+~~~~
+
+The next thing we're going to be is create all the directories we need.
+
+~~~~console
+sudo mkdir -p /var/lib/gitea/{custom,data,indexers,public,log}
+sudo chown git:git /var/lib/gitea/{data,indexers,log}
+sudo chmod 750 /var/lib/gitea/{data,indexers,log}
+sudo mkdir /etc/gitea
+sudo chown root:git /etc/gitea
+sudo chmod 770 /etc/gitea
+~~~~
+
+That last line should make you nervous, that's too permissive for a public setup, but don't worry, as soon as we're done setting up Gitea we'll change the permissions on that directory and the config file inside it. First though let's get Nginx setup to serve Gitea.
+
+### Setup a database and nginx
+
+I use postgresql for gitea. You can also use MySQL, but you're on your own there. Install postgresql if you haven't already:
+
+~~~~console
+sudo apt install postgresql
+~~~~
+
+Now let's create a new postgres user and database for Gitea.
+
+~~~~console
+sudo su postgres
+createuser gitea
+createdb gitea -O gitea
+~~~~
+
+Exist the postgres user shell with `Ctrl+D`. Now let's set up Nginx to serve our Gitea site.
+
+
+
+NOTE: /etc/gitea is temporary set with write rights for user git so that Web installer could write configuration file. After installation is done it is recommended to set rights to read-only using:
+
+chmod 750 /etc/gitea
+chmod 644 /etc/gitea/app.ini
+
+[^1]: You can compile Gitea yourself if you like, there are [instructions on the Gitea site](https://docs.gitea.io/en-us/install-from-source/), but be forewarned its uses quite a bit of RAM to build.