title:Nextcloud and Guix System Server
date: 2023-02-22 17:00
tags: guix nextcloud
summary: Firewalls are hard at first.
---

So I have wanted to run [nextcloud](https://nextcloud.com/) for a while now. In my humble opinion, guix
system makes maintaining websites super easy, so I would prefer to run nextcloud
on guix system. Unfortunately, nextcloud will NOT be packaged in guix anytime
soon for two reasons:

1.  Guix does not currently have a php build system or any php packages, though
    there is a 80% completed [work-in-progress issue.](https://issues.guix.gnu.org/42338) So the php bits of nextcloud
    cannot be packaged properly.
2.  Nextcloud has a lot of javascript dependencies, and javascript is [notoriously
    hard to package for guix.](https://dustycloud.org/blog/javascript-packaging-dystopia/)

It seems like the easiest way to currently run nextcloud on guix system is by
using the [all in one docker image.](https://github.com/nextcloud/all-in-one) Please consider this a guide to set up
running nextcloud on guix system via a linode, which currently costs me about $5
per month.

Note, that while this is the easiest method to run nextcloud, apparently this
all in one docker image has some security issues:

> The AIO image mounts the Docker socket, which is a security risk since it allows
> full access to other container as well as running any new container. It&rsquo;s a bad
> idea and should be avoided.

tl;dr  Here are the 6 simple steps that you need to do:

1.  Set up a [linode guix system server.](https://guix.gnu.org/en/cookbook/en/html_node/Running-Guix-on-a-Linode-Server.html#Running-Guix-on-a-Linode-Server)  `info "Guix Cookbook" RET i linode RET`.
2.  Buy a domain name.  I use [hover.com](https://hover.com).
3.  Point your domain name at your linode IP address.
4.  Set up a basic nginx static website without encryption.  This means that you
    don&rsquo;t want to define `(service certbot-service-type)`.
    
        sudo mkdir -p /srv/www/html/yourdomainname.com
        
        # the command I did was this:
        sudo mkdir -p /srv/www/html/the-nx.com
        
        sudo chgrp -R users /srv
        sudo chmod -R g+rwx /srv
    
    Inside your newly created directory (*srv/www/html/yourdomainname.com*), put
    a simple HTML file and call it &ldquo;index.html&rdquo;. You could use this:
    
        <!doctype html>
        <html class="no-js" lang="">
            <head>
                <meta charset="utf-8">
                <meta http-equiv="x-ua-compatible" content="ie=edge">
                <title>the nx</title>
                <meta name="description" content="">
                <meta name="viewport" content="width=device-width, initial-scale=1">
                <link rel="apple-touch-icon" href="/apple-touch-icon.png">
        
            </head>
            <body>
                <!--[if lt IE 8]>
                    <p class="browserupgrade">
                    You are using an <strong>outdated</strong> browser. Please
                    <a href="http://browsehappy.com/">upgrade your browser</a> to improve
                    your experience.
                    </p>
                <![endif]-->
        
                <p>Hello!</p>
            </body>
        </html>
    
    Now set up a basic nginx configuration for a static website without
    encryption. It will end up looking something like:
    
        (service nginx-service-type
                 (nginx-configuration
                  (server-blocks
                   (list
                    (nginx-server-configuration
                     (server-name '("the-nx.com"))
                     (listen (list "80" "[::]:80"))
                     (root "/srv/www/html/the-nx.com"))))))
    
    Now you need to reconfigure so that the `nginx` user is created:
    
    `sudo guix system reconfigure config.scm`
    
    Now, nginx is running, but you will probably need to give nginx access to
    read the files in your /srv directory.
    
        sudo chown -R nginx /srv
        sudo chmod -R u-rwx /srv
    
    Open up a web browser and go to <http://yourdomainname.com> and check to see
    that you see a basic website.
5.  Now you need to turn your basic static website, into a site that has https
    support.  Now you need to edit your nginx config and add in a certbot config:
    
    Before your `(operating-system ...)` declartion, define this bit of code:
    
        (define %nginx-deploy-hook
          (program-file
           "nginx-deploy-hook"
           #~(let ((pid (call-with-input-file "/var/run/nginx/pid" read)))
               (kill pid SIGHUP))))
    
    Also make sure that you add in a `certbot` service and a modified `nginx`
    service that look like this:
    
        (service certbot-service-type
                 (certbot-configuration
                  (email "mysubscriptions@member.fsf.org")
                  (webroot "/srv/www/")
                  (certificates
                   (list
                    (certificate-configuration
                     (name "the-nx.com")
                     (domains '("the-nx.com" "www.the-nx.com"))
                     (deploy-hook %nginx-deploy-hook))))))
        
        (service nginx-service-type
                 (nginx-configuration
                  (server-blocks
                   (list
                    (nginx-server-configuration
                     (server-name '("the-nx.com"))
                     (listen (list "80"
                                   "443 ssl http2"
                                   "[::]:80"
                                   "[::80]:443 ssl http2"))
                     (root "/srv/www/html/the-nx.com")
                     (ssl-certificate "/etc/letsencrypt/live/the-nx.com/fullchain.pem")
                     (ssl-certificate-key "/etc/letsencrypt/live/the-nx.com/privkey.pem")
                     (locations
                      (list
                       (nginx-location-configuration ;; for certbot
                        (uri "/.well-known")
                        (body (list "root /srv/www;"))))))))))
    
    Now we will have to reconfigure again to set up certbot:
    
        sudo guix system reconfigure config.scm
        
        # tell certbot to set up our certificates
        sudo /var/lib/certbot/renew-certificates
    
    Now you should be able to go to <https://yourdomainname.com> and see your site
    in glorious encrypted mode!
6.  Modify your guix config based on my [the-nx.com-current-config.scm](https://notabug.org/jbranso/linode-guix-system-configuration/src/master/the-nx.com-current-config.scm). 
    You will need to enable these services `(dbus-service)`, `(service
       docker-service-type)`, `(elogind service)`, `(service certbot-service-type)`,
    and `(service nginx-service-type)`.



I just ran this command, and my local nextcloud just started working.

    sudo docker run \
    --sig-proxy=false \
    --name nextcloud-aio-mastercontainer \
    --restart always \
    --publish 80:80 \
    --publish 8080:8080 \
    --publish 8443:8443 \
    --volume nextcloud_aio_mastercontainer:/mnt/docker-aio-config \
    --volume /var/run/docker.sock:/var/run/docker.sock:ro \
    nextcloud/all-in-one:latest

The following is the same quick guide as above, but has more details:

I decided to create a new linode image following the linode cookbook guide, and
I noticed a tiny error in the guide:

`sudo apt-get install gpg` failed.  It worked after I ran `sudo apt-get update`.

Also the basic config example needs to migrate to the new <swap-space> record.
It gave me this warning message:

/root/config.scm:11:0: warning: List elements of the field &rsquo;swap-devices&rsquo; should
now use the <swap-space> record, as the old method is deprecated. See &ldquo;(guix)
operating-system Reference&rdquo; for more details.

The cookbook guide also should probably mention that you may need to login to
the server for the first time using linode&rsquo;s weblish, and set up the root passwd
with `passwd`. Then set up your user password with `passwd <username>`.

Now that we have a basic site set up, let&rsquo;s set up certbot and the nginx services:

    (service certbot-service-type
             (certbot-configuration
              (email "mysubscriptions@member.fsf.org")
              (webroot "/srv/www/")
              (certificates
               (list
                (certificate-configuration
                 (name "the-nx.com")
                 (domains '("the-nx.com" "www.the-nx.com"))
                 (deploy-hook %nginx-deploy-hook))))))
    
    (nginx-configuration
     (server-blocks
      (list
       (nginx-server-configuration
        (server-name '("the-nx.com"))
        (listen (list "80"
                      "443 ssl http2"
                      ;;"[::]:80"
                      ;;"[::80]:443 ssl http2"
                      ))
        (root "/srv/www/html/the-nx.com")
        (ssl-certificate "/etc/letsencrypt/live/the-nx.com/fullchain.pem")
        (ssl-certificate-key "/etc/letsencrypt/live/the-nx.com/privkey.pem")
        (locations
         (list
          (nginx-location-configuration ;; for certbot
           (uri "/.well-known")
           (body (list "root /srv/www;")))))))))

Now let&rsquo;s reconfigure and get a certbot certificate.  `ssh` into the-nx.com and
run these commands:

    sudo guix system reconfigure the-nx.com-current-config.scm
    
    # tell certbot to set up our certificates
    sudo /var/lib/certbot/renew-certificates

So now my server has a valid certificate. It is time change the nginx
configuration to proxy incoming requests to the docker all in one image.

Ok, maybe I can use sexpressions to tell nginx to redirect all incoming traffic
to `the-nx.com` to the docker nextcloud image:

    (nginx-location-configuration
     (uri "/")
     (body
      (list
       "proxy_pass http://127.0.0.1:9000;\n"
       "proxy_set_header X-Real-IP $remote_addr;\n"
       "proxy_set_header Host $host;\n"
       "proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n"
       "client_max_body_size 0;\n"
       "# Websocket\n"
       "proxy_http_version 1.1;\n"
       "proxy_set_header Upgrade $http_upgrade;\n")))

I am going to deploy this image, and take a look at the generated nginx
configuration file.  I ran this command on my T400 laptop:

`guix deploy the-nx.com-current-config.scm`

Well, that&rsquo;s super annoying. I do not know which nginx.conf file is the right
one:

    find /gnu/store -name '*nginx.conf'

    /gnu/store/7m1ygzqk6njn5mywqmhwbydbb2z4b9li-nginx.conf
    /gnu/store/0gcfj61q4943h94jdqq7i9y0a0v9jr9q-nginx.conf
    /gnu/store/4mzrp39w5i4v94kxf98gxc13ws79l88n-nginx.conf
    /gnu/store/0nia2iqfw63ziasibbgq321wr9b3152n-nginx.conf
    /gnu/store/pf8d0sj1yf9b2ndsbc61yj3h6rp4pck2-nginx.conf
    /gnu/store/9nra62v41wsk08xf3msw5a1z35gji2gx-nginx-1.23.2/share/nginx/conf/nginx.conf
    /gnu/store/4b1szfyn0snwzf3lm1snvaapk6diz3yq-nginx.conf
    /gnu/store/fv5rg3nf5999vyg6qvp4sbgjysnkn1fc-nginx.conf
    /gnu/store/vmjwj2zwblcz4wx2whsmxdfc7zxcgjh5-nginx.conf
    /gnu/store/n3m2lihq9cjm6mxdln57q5nrbjgz53s6-nginx.conf
    /gnu/store/jnl72hx0papzb42kbd1f19qx35w76lmg-nginx-1.23.2/share/nginx/conf/nginx.conf

I guess I will reboot, run `guix system delete-generations` and `guix gc`, and
run the above command again:

    find /gnu/store -name '*nginx.conf'

    /gnu/store/7m1ygzqk6njn5mywqmhwbydbb2z4b9li-nginx.conf
    /gnu/store/jnl72hx0papzb42kbd1f19qx35w76lmg-nginx-1.23.2/share/nginx/conf/nginx.conf

Well that looks promising.  Let's check out my nginx.conf file.


    cat /gnu/store/i2mzdhg8wlbxv7iza8y4qk5v0vmvp27q-nginx.conf

    user nginx nginx;
    pid /var/run/nginx/pid;
    error_log /var/log/nginx/error.log info;
    events { }
    http {
        client_body_temp_path /var/run/nginx/client_body_temp;
        proxy_temp_path /var/run/nginx/proxy_temp;
        fastcgi_temp_path /var/run/nginx/fastcgi_temp;
        uwsgi_temp_path /var/run/nginx/uwsgi_temp;
        scgi_temp_path /var/run/nginx/scgi_temp;
        access_log /var/log/nginx/access.log;
        include /gnu/store/jnl72hx0papzb42kbd1f19qx35w76lmg-nginx-1.23.2/share/nginx/conf/mime.types;
    
        server {
          listen 443 ssl http2;
          server_name the-nx.com ;
          ssl_certificate /etc/letsencrypt/live/the-nx.com/fullchain.pem;
          ssl_certificate_key /etc/letsencrypt/live/the-nx.com/privkey.pem;
          root /srv/www/html/the-nx.com;
          index index.html ;
          server_tokens off;
    
          location /.well-known {
            root /srv/www;
          }
          location / {
            proxy_pass http://127.0.0.1:9000;
    
            proxy_set_header X-Real-IP $remote_addr;
    
            proxy_set_header Host $host;
    
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    
            client_max_body_size 0;
    
            # Websocket
    
            proxy_http_version 1.1;
    
            proxy_set_header Upgrade $http_upgrade;
    
          }
    
        }
        server {
          listen 80;
          listen [::]:80;
          server_name the-nx.com www.the-nx.com ;
          root /srv/http;
          index index.html ;
          server_tokens off;
    
          location /.well-known {
            root /srv/www/;
          }
          location / {
            return 301 https://$host$request_uri;
          }
    
        }
    
    }
    
    
The generated configuration seems pretty wonky, and I am suprised that nginx is
still running, but it is still running.  And I suppose that it should work.

I was able to get nextcloud to start with this command:

    sudo docker run --sig-proxy=false --name nextcloud-aio-mastercontainer \
     --restart always \
     --publish 8080:8080 \
     -e APACHE_PORT=9000 \
     --volume nextcloud_aio_mastercontainer:/mnt/docker-aio-config \
     --volume /var/run/docker.sock:/var/run/docker.sock:ro  \
     nextcloud/all-in-one:latest

So now I can login at the-nx.com:8080 and configure various stuff. Also I really
need to set up a firewall. That&rsquo;s probably a really good idea.  Also what&rsquo;s nice
about this docker image is that it will start itself if you update the guix
system server and reboot.

MORE BONUS CONTENT:

If you see this blog post, and you decide to set up your nextcloud on a guix
system server, and if your nginx config doesn&rsquo;t seem to be proxying requests to
your docker container, then you may follow these steps to delete the docker
image and start over:

This [page](https://help.nextcloud.com/t/aio-this-site-can-t-provide-a-secure-connection/128478/5) has some good commands for deleting the docker image and starting
over:

    sudo docker stop nextcloud-aio-mastercontainer && \\
    sudo docker rm nextcloud-aio-mastercontainer && \\
    sudo docker container prune -f && \\
    sudo docker volume prune -f && \\
    sudo docker pull nextcloud/all-in-one:latest

Ok, so it looks like the nextcloud all in one documentation has a [page](https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md) for
understanding the reverse proxy.

It would also be nice to get my nextcloud image to sync my contacts.  I probably just need to add in another nginx
location line for that.  That will be a project for another day.

